Você está na página 1de 24

Atividade A2

Análise de Algoritmos Recursivos, Paradigmas e Projetos de Algoritmos, Problemas P


e NP

Data limite de entrega: 18 de Novembro

Grupo de 1 a 4 pessoas
Integrantes por ordem de RGM
RGM Nome

1. A sequência de Fibonacci é uma sequência de números inteiros que começa em 1, a que se


segue 1, e na qual cada elementos subsequente é a soma dos dois elementos anteriores. A
função fib a seguir calcula o n-ésimo elemento da sequência de Fibonaci:
unsigned int fib (unsigned int n){

if (n < 2)

return 1;
return fib (n-2) + fib (n-1);

}
Considerando a implementação acima, avalie as afirmações a seguir.
I. A complexidade de tempo da função fib é exponencial no valor de n.
II. A complexidade de espaço da função fib é exponencial no valor de n.
III. É possível implementar uma versão iterativa da função fib com complexidade de
tempo linear no valor de n e complexidade de espaço constante.

Identifique as afirmações Verdadeiras e Falsas e JUSTIFIQUE sua resposta para cada afirmativa.

2. Considere a função recursiva F a seguir, que em sua execução chama a função G:


1. void F(int n) {
2. if (n > 0) {
3. for (int i = 0; i < n; i++) {
4. G(i);
5. }
6. F(n / 2);
7. }
8. }

Com base nos conceitos de teoria da complexidade, avalie as afirmações a seguir.


I. A equação de recorrência que define a complexidade da função F é a mesma do
algoritmo clássico da ordenação mergesort.
II. O número de chamadas recursivas da função F é o Ɵ(log n).
III. O número de vezes que a função G da linha 4 é chamada é O(n log n).

Identifique as afirmações Verdadeiras e Falsas e JUSTIFIQUE sua resposta para cada afirmativa.

3. Os números de Fibonacci constituem uma sequência de números na qual os dois primeiros


elementos são 0 e 1 e os demais, a soma dos dois elementos imediatamente anteriores na
sequência. Como exemplo, a sequência formada pelos 10 primeiros números de Fibonacci
é 0, 1, 1, 2, 3, 5, 8, 13, 21, 34. Mais precisamente, é possível definir os números de
Fibonacci pela seguinte relação de recorrência:
fib(n) = 0, se n = 0
fib(n) = 1, se n = 1
fib(n) = fib(n-1) + fib(n-2), se n > 1

Abaixo, apresente-se uma implementação em linguagem funcional para essa relação de


recorrência:
fib :: Integer -> Integer
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib(n-2)
Considerando que o programa acima não reutilize resultados previamente computados
Quantas chamadas são feitas à função fib para computar fib 5?

4. (Baseadas nas Questões do ENADE 2011 e POSCOMP 2008). Algoritmos criados para
resolver um mesmo problema podem diferir de forma drástica quanto a sua eficiência.
Para evitar este fato, são utilizadas técnicas algorítmicas, isto é, conjunto de técnicas que
compreendem os métodos de codificação de algoritmos de forma a salientar sua
complexidade, levando-se em conta a forma pela qual determinado algoritmo chega à
solução desejada.

Considerando os diferentes paradigmas e técnicas de projeto de algoritmos, o algoritmo


abaixo:
Módulo OQueEuFaco(n)
início
Inteiro F[n+1], i;
F[0]  0;
F[1]  1;
Para ( i  2; i <= n; i++) faça
F[i]  F[i-1] + F[i-2]
fim-para
retorna F[n];
fim.
E as afirmações:
I. O algoritmo OQueEuFaco(n) encontra os n números da sequência de Fibonacci
retornando todos os números da sequência.
II. O Algoritmo OQueEuFaco utiliza O(n) de espaço durante a sua execução.
III. O Algoritmo OQueEuFaco(n) tem complexidade O(n).
IV. O Algoritmo OQueEuFacoRec tem a mesma funcionalidade que o algoritmo
OQueEuFaco e utiliza a recursividade na sua implementação:

Módulo OQueEuFacoRec ( n )
início
se (n < 2) retorna n;
senão retorna OQueEuFacoRec (n - 1)+ OQueEuFacoRec (n - 2);
fim

V. O Algoritmo OQueEuFacoRec tem eficiência polinomial, mas é menos eficiente que o


algoritmo OQueEuFaco.

Identifique as afirmações Verdadeiras e Falsas e JUSTIFIQUE sua resposta para cada afirmativa.

5. (Baseadas nas Questões do ENADE 2011 e POSCOMP 2008). Algoritmos criados para
resolver um mesmo problema podem diferir de forma drástica quanto a sua eficiência.
Para evitar este fato, são utilizadas técnicas algorítmicas, isto é, conjunto de técnicas que
compreendem os métodos de codificação de algoritmos de forma a salientar sua
complexidade, levando-se em conta a forma pela qual determinado algoritmo chega à
solução desejada.
Considerando os diferentes paradigmas e técnicas de projeto de algoritmos, o algoritmo
abaixo:

Módulo OQueEuSou (A, i, f)


Início
Se (i = f) retorna i;
Senão
p  OqueEuSou (A, i, piso(( i+f)/2))
q  OqueEuSou (A, piso(( i+f)/2) + 1, f)
se A[p] <= A[q] retorna p
senão retorna q;
fim
Obs.: considere que n = f - i + 1 e o número de comparações entre os elementos de um vetor
A, numa execução de OQueEuSou( A, i, f).
I. O algoritmo OQueEuSou(n) retorna o índice do elemento máximo do vetor.
II. O algoritmo OQueEuSou(n) utiliza como técnica de programação a especialização da
técnica da divisão e conquista que procura sempre manter o balanceamento na
subdivisão de um problema em partes menores e iguais.
III. O algoritmo OQueEuSou tem complexidade O(nlog 2n).
IV. O algoritmo OQueEuSouNaoRec realiza a mesma funcionalidade que o algoritmo
OQueEuSou, mas não se utiliza da recursividade.

Módulo OQueEuSouNaoRec ( A, n )
início
posMax ¬ 0;
para (i ¬ 1; i £ n-1; i++) faça
se (A[posMax} < A[i]) então
posMax ¬ i
fim-se
retorne posMax;
fim
V. A complexidade do algoritmo OQueEuSouNaoRec é O(n).

Identifique as afirmações Verdadeiras e Falsas e JUSTIFIQUE sua resposta para cada afirmativa.
6. (Baseadas nas Questões do ENADE 2005 e POSCOMP 2010). Considere que,
durante a análise de um problema de programação, tenha sido obtida a seguinte
fórmula recursiva que descreve a solução para o problema.

0 , se n=1.
T ( n )=
{()
T
n
2
+ n+1 , se n> 1.

Utilizando o Teorema Mestre, encontre a complexidade θ (Theta) associada a esse


problema.

7. (Baseadas nas Questões do ENADE 2005 e POSCOMP 2010). Considere que,


durante a análise de complexidade de um algoritmo para um problema de
programação, tenha sido obtida a seguinte equação de recorrência.

1 , se n=1.
T ( n )=
{9T
n
3() + n2 , se n> 1.

Então, utilizando os instrumentos de resolução de equações deste tipo, determine a


complexidade dessa solução.

8. (Baseadas nas Questões do ENADE 2005 e POSCOMP 2010). Considere que,


durante a análise de um problema de programação, tenha sido obtida a seguinte
fórmula recursiva que descreve a solução para o problema.

1, se n=1.
T ( n )=
{2T ( n−1 ) +1 , se n>1.

Então, utilizando a técnica da substituição, determine a complexidade assintótica O-


Grande da solução desse problema.

9. (Baseadas nas Questões do ENADE 2005 e POSCOMP 2010). Considere que,


durante a análise de um problema de programação, tenha sido obtida a seguinte
fórmula recursiva que descreve a solução para o problema.

0 , se n=1.
T ( n )=
{T ( n−1 )+ n+c , se n> 1.

Então, utilizando a técnica da substituição, determine a complexidade assintótica O-


Grande da solução desse problema.
10. (Baseada em questão do ENADE 2008). Os números de Fibonacci constituem uma
sequencia de números na qual os dois primeiros elementos são 0 e 1 e os demais, a
soma dos dois elementos imediatamente anteriores na sequencia. Como exemplo,
a sequencia formada pelos 10 primeiros números de Fibonacci é: 0, 1, 1, 2, 3, 5, 8,
13, 21, 34. Mais precisamente, é possível definir os números de Fibonacci pela
seguinte relação de recorrência:

fib (n) = 0, se n = 0
fib (n) = 1, se n = 1
fib (n) = fib (n - 1) + fib (n - 2), se n > 1

Abaixo, apresenta-se uma implementação em Java para essa relação de recorrência:

public int fib( int n ){


if (n < 2) return n;
else return fib(n - 1)+fib(n - 2);
}

Considerando o programa acima, pergunta-se: Quantas chamadas são feitas à função


fib para computar fib( 6 )?

11. (Baseada em questão do ENADE 2008 e POSCOMP 2011). Considere o algoritmo


abaixo:

inteiro k;
modulo f( inteiro n )
início
se (n < 2) então
k = 0;
retorna n;
senão
retorna f(n-1, p) + f(n-2, q);
k = p + q + 1;
fim-se
escreve (n, " ", k, ";");
fim
Considerando o algoritmo f, pergunta-se: Quantas chamadas são feitas à função f para
computar f ( 6 )?
12. (Baseada em questão do POSCOMP 2010). Considere o algoritmo Rascunho
recursivo que calcula o produto de dois números naturais u e v de tamanho n:

Rascunho (u, v, n)
início
Se (n == 1) então retorna u * v;
Senão
m  n/2;
p  piso ( u / 10m )
q  u mod 10m;
r  piso( v / 10m)
s  v mod 10m
pr  Rascunho(p, r, m)
qs  Rascunho(q, s, m)
ps  Rascunho(p, s, m)
qr  Rascunho(q, r, m)
x  pr * 102*m + (ps + qr) * 10m + qs
retorna x;
fim-se
fim
Seja T(n) o tempo de execução do algoritmo para as entradas u, v e n. Assim,
pede-se:
a. Qual a equação de recorrência do algoritmo Rascunho, tendo por base as
comparações.
b. A partir da Equação obtida no item anterior, determine a complexidade do
algoritmo rascunho.

13. Considere o algoritmo PROC a seguir:

PROC (n)
início
se n <= 1 então
retorna 1 + n;
senão
retorna PROC(n/2) + PROC(n/2);
fim se
fim

Considerando o algoritmo PROC para uma entrada n > 0, onde n é um número natural.
pede-se:
a. Qual a sua equação de recorrência, tendo por base as comparações.
b. A partir da Equação obtida no item anterior, determine a sua complexidade.

14. Seja o algoritmo abaixo:

função inteiro f(inteiro n)


início
se ((n = 0) ou (n = 1) então retorna n.
senão
início
inteiro a = f( (n+1) / 2);
inteiro b = f( (n+1) / 2 - 1);
se (n % 2 = 0) então retorna a * (a + 2 * b)
senão retorna a * a + b * b;
fim
fim.

E as afirmações:

I. O algoritmo f foi elaborado segundo o paradigma divisão e conquista.


II. Se realizarmos a chamada f(5) o resultado será 5.
III. A complexidade desse algoritmo é O(n).
IV. O algoritmo f2 abaixo resolve o mesmo problema que f e sua complexidade é
O(lg n).

função inteiro f2( inteiro n)

início

se n < 2 então retorna n;

senão retorna f2(n-1) + f2(n-2);

fim.

V. O algoritmo f encontra o n-ésimo termo da sequência de fibonacci, considerando o


zero-ésimo termo (primeiro temo da sequencia) como sendo o valor 0.

Considerando o algoritmo f e as afirmações I a V, identifique quais são Verdadeiras ou


falsas e JUSTIFIQUE sua resposta em cada uma delas.

15. O trecho de algoritmo para calcular a n n que utiliza uma repetição para a contagem
das multiplicações é dado por:

função inteiro n_elevado_n ( inteiro n)


início
inteiro res, i;
res ← 1;
para (i ← 1; i ≤ n; i++) faça
res ← res * n;
retorna res;
fim.

Se n for um múltiplo de 2, como: 1, 2, 4, 8, 16, 32,...


O algoritmo anterior que calcula nn pode ser reescrito para:

função inteiro n_elevado_n2( inteiro n)


início
inteiro res, i;
res ← n
para (i ← 1; i < n; i= i *2) faça
res ← res * res;
retorna res;
fim.
A afirmação correta sobre esses algoritmos é:

A. O algoritmo n_elevado_n tem complexidade O(lg n).


B. O algoritmo n_elevado_n2 tem complexidade O(n).
C. O algoritmo n_elevado_n2 é um algoritmo ótimo e tem complexidade O(lg lg n).
D. O algoritmo n_elevado_n tem complexidade O(n), mas não é ótimo quando n é
múltiplo de 2.
E. O algoritmo n_elevado_n2 não é um algoritmo ótimo quando n é múltiplo de 2 e
tem complexidade O(lg n).

16. (Baseada em questão do POSCOMP 2015 e 2016). Sabe-se que o tempo de


execução T(n) dos algoritmos A, B e C, em que n é o tamanho da entrada, são
dados pela equação de recorrência

A) T(nA) = 8T(n/2)+q*n se n > 1, T(1) = p, e que p e q são constantes arbitrárias.


B) T(nB) = 4T(n/2) + n2 se n > 1, T(1) = 1 .
C) T(nC) = 2T(n/4) + n3, se n > 1, T(1) = 2 .

Também sabe-se que muitas das recorrências que acontecem na análise de


algoritmos de divisão e conquista têm a forma F(n) = a F(n/b) + c*n k para F(n)
assintoticamente não decrescente, a, b, k ϵ N, a >= 1, b >= 2, k >= 0, e c ϵ R +. Nessas
condições, de acordo com o Teorema Mestre,

 Se (log2 a/ log2 b) > k, então F(n) está em Θ (nlog2 a/ log2 b),


 Se (log2 a/ log2 b) = k, então F(n) está em Θ (nk log2 n),
 Se (log2 a/ log2 b) < k, então F(n) está em Θ (nk ),

Pede-se:

a) Qual a complexidade de Θ dos algoritmos A, B e C pela definição do teorema


mestre acima?
b) Coloque a complexidade Θ dos algoritmos A, B e C em ordem crescente (da
menor função de complexidade para a maior, por exemplo T(nA) < T(nB) =
T(nC)).

17. As técnicas de projetos de algoritmos são essenciais para que os desenvolvedores


possam implementar software de qualidade. Essas técnicas descrevem os
princípios que devem ser adotados para se projetar soluções algorítmicas para um
dado problema. Entre as principais técnicas, destacam-se os projetos de algoritmos
por tentativa e erro, divisão e conquista, programação dinâmica e algoritmos
gulosos.

Nesse contexto, considerando que o algoritmo abaixo.Módulo OqueEuSou (A, i, f)

Início
Se (i = f) retorna i;
Senão
p  OqueEuSou (A, i, piso(( i+f)/2));
q  OqueEuSou (A, piso(( i+f)/2) + 1, f);
se A[p] <= A[q] retorna p;
senão retorna q;
fim

Pede-se:
a. Qual técnica de projeto algoritmos foi utilizada. Porquê ?
b. Suponha que o tamanho n do vetor A é dado por n = f – i + 1. Realize o teste do
módulo supondo o vetor A[ 8, 2, 3, 5, 1, 9] e determine o que será retornado com a
chamada OqueEuSou(A, 0, 5)
c. O que faz o módulo OqueEuSou? Descreva sua funcionalidade.
d. Forneça uma equação de recorrência T(n) para este módulo, considerando
somente a operação comparação entre os elementos do vetor A. (1 operação)
e. Resolva a equação de recorrência por qualquer das técnicas estudadas e obtenha
a complexidade assintótica Theta.

18. Considere que, a seguir, no algoritmo “quadrado” n representa a metade do


tamanho de um lado, x e y são o centro do quadrado e gera a figura abaixo desse
algoritmo.
void quadrado(int x,int y, int n){

if ( n > 0 ) {
quadrado(x-n, y+n, n div 2);
quadrado(x+n, y+n, n div 2);
quadrado(x-n, y-n, n div 2);
quadrado(x+n, y-n, n div 2);
desenha(x, y, n); // desenha o quadrado }
}
a) Analisando somente a operação de comparação, apresente a equação de
recorrência desse módulo.

b) Qual paradigma de programação foi utilizado nesse módulo? Porquê?

c) Determine a complexidade desse algoritmo em função de Θ. (Utilize qualquer


método para obter a complexidade).

19. Um tipo especial de função é aquele que contém, em sua descrição, uma ou mais
chamadas a si mesma. Uma função dessa natureza é denominada recursiva. Seja a
função abaixo.

função inteiro ENIGMA (inteiro n, inteiro f)


início
inteiro aux1, aux2;
se (n < f) então retorna ENIGMA (n, f div 10);
se (n = 0) então retorna n;
senão
início
aux1 = n div f;
n = n mod f;
f = f div 10;
aux2 = ENIGMA (n, f);
retorna aux2 * 10 + aux1;
fim
fim

Obs.: div é o quociente de uma divisão sobre números inteiros e mod é o resto de uma
divisão inteira.
Considerando o algoritmo ENIGMA, pergunta-se:
a) Realizar os testes para as chamadas ENIGMA( 9825, 1000) e ENIGMA( 214, 100) e
informar o que será retornado em cada chamada. Obs.: os testes devem constar e
fazer parte da resolução.
b) Qual a funcionalidade da função ENIGMA? Não descrever o que faz cada comando,
mas qual sua utilidade.
c) Considerando somente a operação de comparação (n = 0) para o algoritmo
recursivo ENIGMA, determine a equação de recorrência T(n) para n >= 0. Também,
considere que o operador “div” e “/” tem a mesma funcionalidade.
d) Tendo por base a equação de recorrência obtida no item anterior, resolva-a pelo
teorema mestre e encontre a complexidade assintótica Theta desse algoritmo.
20. Considerando que certo algoritmo forneceu a equação de recorrência abaixo:

n = 2, T(2) = 1 e n > 2, T(n) = T(n-1) + n.

Determine:
a) A equação de complexidade T(n) a partir da equação de recorrência.

b) O O-grande desse algoritmo pelas suas propriedades.

21. Considerando que certo algoritmo forneceu a equação de recorrência abaixo:

n = 0, T(0) = 1, n = 1, T(1) = 2 e n > 1, T(n) = T(n-1) + n.

Determine:
a) A equação de complexidade T(n) a partir da equação de recorrência.
b) O O-grande desse algoritmo pelas suas propriedades.

22. Considere o algoritmo abaixo:

função inteiro f( inteiro n, REF inteiro k )


início
inteiro m, p, q;
se (n < 2) então
k = 0;
retorna n;
senão
m = f(n-1, p) + f(n-2, q);
k = p + q + m;
fim-se
escreve (n, " ", k, ";");
retorna m;
fim
Obs.: REF indica passagem de parâmetro por referência.
Considerando o algoritmo f, pergunta-se:

a) Quantas chamadas são feitas à função f para computar f ( 5, 0 )?


b) Quais os valores serão escritos para a chamada f(3, 0) ?
c) Considerando somente a operação de comparação para o algoritmo recursivo f
determine a equação de recorrência T(n) para n >= 0.

23. (Baseada em questão do POSCOMP 2015). Quais destes algoritmos de ordenação


têm a classe de complexidade assintótica, no pior caso, em O(n.log n) ?

a) QuickSort e SelectionSort
b) QuickSort, MergeSort, e HeapSort
c) QuickSort e BubbleSort
d) QuickSort, MergeSort e SelectionSort
e) MergeSort e HeapSort
24. (Baseada em questão do POSCOMP 2015). Muitas das recorrências que acontecem
na análise de algoritmos de divisão e conquista têm a forma F(n) = a F(n/b) + c*nk
para F(n) assintoticamente não decrescente, a, b, k ϵ N, a >= 1, b >= 2, k >= 0, e c ϵ
R+. Nessas condições, de acordo com o Teorema Mestre,

 Se (log2 a/ log2 b) > k, então F(n) está em Θ (nlog2 a/ log2 b),


 Se (log2 a/ log2 b) = k, então F(n) está em Θ (nk log2 n),
 Se (log2 a/ log2 b) < k, então F(n) está em Θ (nk ),
Considere os algoritmos A, B e C, que são descritos, respectivamente pelas equações de
recorrências:

FA(n) = 8F(n/4) + n ; FB(n) = 4F(n/2) + n2 ; FC(n) = 2F(n/4) + n3 ;

Dado que log22 = 1, log24 =2 e log28 = 3, pede-se:

a) Qual a complexidade de Θ dos algoritmos A, B e C pela definição do teorema


mestre acima?
b) Coloque a complexidade Θ dos algoritmos A, B e C em ordem crescente (da menor
função de complexidade para a maior, por exemplo Θ(FA) < Θ (FC) = Θ (FB)).

25. (Baseada em questão do POSCOMP 2015). Muitas das recorrências que


acontecem na análise de algoritmos de divisão e conquista têm a forma F(n) = a
F(n/b) + c*nk para F(n) assintoticamente não decrescente, a, b, k ϵ N, a >= 1, b >= 2,
k >= 0, e c ϵ R+. Nessas condições, de acordo com o Teorema Mestre,

 Se (log a/ log b) > k, então F(n) está em Θ (nlog a/ log b),


 Se (log a/ log b) = k, então F(n) está em Θ (nk log n),
 Se (log a/ log b) < k, então F(n) está em Θ (nk ),

Considere os algoritmos A, B e C, que são descritos, respectivamente pelas equações de


recorrências:
FA(n) = 4F(n/2) + n2 ; FB(n) = 2F(n/4) + n3 ; FC(n) = 8F(n/4) + n ;

Dado que log22 = 1, log24 =2 e log28 = 3, pede-se:

a) Qual a complexidade de Θ dos algoritmos A, B e C pela definição do teorema


mestre acima?
b) Coloque a complexidade Θ dos algoritmos A, B e C em ordem crescente (da menor
função de complexidade para a maior, por exemplo Θ(FA) < Θ (FC) = Θ (FB)).

26. Considere os 5 algoritmos abaixo que determinam o enésimo termo da


sequência de Fibonacci.
função inteiro fib_1( int n ) função inteiro fib_2(n)
início início
se (n < 2) retorna n; inteiro a, b, c, d, i = n-1;
senão se (n <= 0) retorna 0;
início (a, b) = (1, 0);
inteiro ant = 1, preant = 1, atual; (c, d) = (0, 1);
para (inteiro i = 3; i <= n; i++) enquanto (i > 0) faça
início início
atual = ant + preant; se (i mod 2 == 0) então
preant = ant; (a, b) = (db + ca, d(b+a) + cd)
ant = atual; (c,d) = (c2 + d2, d (2c + d))
fim i = i div 2;
retorna atual; fim
fim retorna a + b;
fim fim.
função inteiro fib_3( inteiro n ) função inteiro fib_4( inteiro n )
início início
se ((n == 0) ou (n == 1) então retorna n. inteiro v[n+1], i = 1;
senão v[0] = 0;
início v[1] = 1;
inteiro a = fib_3( (n+1) / 2); enquanto (i < n) faça
inteiro b = fib_3( (n+1) / 2 - 1); início
se (n mod 2 == 0) então retorna a * (a + 2 * b) v[i+1] = v[i] + v[i-1];
senão retorna a * a + b * b; i = i + 1;
fim fim
fim. retorna v[n];
fim.

função inteiro fib_5( inteiro n)


início
se (n < 2) então retorna n;
senão retorna fib_5(n-1) + fib_5(n-2);
fim.

a) Indique qual paradigma ou técnica de programação foi utilizada na construção de


cada algoritmo. (Considere os termos: algoritmo iterativo, recursividade, tentativa e
erro, divisão e conquista, programação dinâmica, algoritmos gulosos, algoritmos
aproximados/heurísticas).
b) Baseado nos estudos realizados em sala, apresente as complexidades (O-Grande)
de cada um dos algoritmos.(Obs.: Não precisa calcular, basta apresentar o O-
Grande)
c) Utilizando o algoritmo fib_4, determine a equação de complexidade (T(n))
considerando todas as operações primitivas. (Supor que a declaração "inteiro v[n+1]"
contém 2 operações primitivas).
d) Determine a equação de recorrência T(n) para o algoritmo fib_3 considerando
somente a operação de comparação, ou seja, as comparações: ((n==0) ou (n==1))
e (n mod 2 == 0).

e) A partir equação de recorrência da alternativa d e utilizando o método da


substituição, determine o O-grande (complexidade) do algoritmo fib_3.

27. O problema da Árvore Parcial de Custo Mínimo pode ser resolvido pelo
algoritmo de PRIM. De forma resumida, esse algoritmo:
- Constrói uma sub-árvore que se inicia unindo um vértice qualquer a
seu vizinho mais próximo;
- No início cada vértice é uma sub-árvore, escolhendo cada um deles
para iniciar o processo;
- Seja Ti Ì V o conjunto de vértices da sub-árvore na iteração i e seja
(v, w) | v Î Ti, w Î V – Ti a aresta de menor valor entre V – Ti e Ti.
- Unem-se o vértice w e a aresta (v,w) à sub-árvore vigente, cujo
conjunto de vértices se torna: Ti+1 = Ti È {w}
- O processo termina quando atingimos todos os vértices (T n = V)
Considerando o funcionamento desse algoritmo, pede-se:
a) Qual paradigma ou técnica de programação é utilizada para
solucionar o problema?
b) Justifique.

28. Uma heurística é um algoritmo que pode produzir um bom resultado, ou até
mesmo obter a solução ótima, mas pode também não produzir solução
alguma ou uma solução que está distante da solução ótima.
Considerando a heurística para o problema do Caixeiro Viajante em um
grafo:
1. Inicie em um vértice arbitrário.
2. Procure o vértice mais próximo do último vértice adicionado que não
esteja no caminho e adicione ao caminho a aresta que liga esses dois
vértices.
3. Quando todos os vértices estiverem no caminho, adicione uma aresta
conectando o vértice inicial e o último vértice adicionado.
E o grafo exemplo:

0
5 1

4 2
3

a. Determine o caminho e o comprimento desse caminho;


b. Utilizando esse algoritmo, o caminho pode não ser ótimo? Por quê?

29. Quanto à análise de algoritmos, considere as afirmativas a seguir.


I. A programação dinâmica pode levar a soluções eficientes para algoritmos
recursivos com complexidade exponencial.
II. Os algoritmos tentativa e erro são impraticáveis com solução recursiva, pois são
aplicados exaustivamente.
III. Um algoritmo recursivo tem tempo de execução inferior à codificação iterativa
para a solução do mesmo problema.
IV. Uma árvore binária de pesquisa é adequada para a solução de problemas de
natureza recursiva.
Dizer se cada afirmativa é verdadeira ou falsa, justificando cada uma.

30. Considere o Algoritmo Abaixo:


módulo sort ( inteiro A[n], inteiro i, inteiro j){ // Considere n uma potência de 3
início
se i < j então
k = ((j-i) + 1 / 3;
Sort2 (A, i, i + k – 1);
Sort2 (A, i+k, i + 2k – 1);
Sort2 (A, i, i + 2k, j);
Merge(A, i, i+k, i+2k, j); // Suponha um custo associado ao Merge de 5n/3 - 2
fim-se
fim

Pede-se:
a. Escreva uma EQUAÇÃO DE RECORRÊNCIA T(n) que descreva este
comportamento.
b. Encontre o Theta pelo Teorema Mestre.

31. Seja o algoritmo da sequencia de Fibonacci abaixo que utiliza a divisão e


conquista, pergunta-se:

a) Qual o Fibonacci(5)? Calcule e mostre o funcionamento da recursividade por meio


da árvore de execução.
b) Encontre a Equação de Recorrência T(n) considerando somente as operações de
comparação, ou seja, 1 (uma) para o primeiro if e mais 1 (uma) para o segundo if.
c) Qual a sua complexidade (O-Grande)?

32. Com relação aos métodos de ordenação, relacione a coluna da esquerda com
a coluna da direita.

Assinale a alternativa que contém a associação correta:


a) I-A, II-D, III-B, IV-C, V-E
b) I-B, II-A, III-E, IV-E, V-D
c) I-B, II-A, III-E, IV-D, V-C
d) I-C, II-A, III-D, IV-B, V-E
33. A programação dinâmica calcula a solução para todos os problemas partindo
dos subproblemas menores para os maiores, armazenando os resultados em
uma tabela.

Esta técnica pode ser utilizada no produto de matrizes na tentativa de otimizar o


número de operações realizadas, ou seja, usando a programação dinâmica é possível
obter um algoritmo O(n3)

Considere o produto de uma matriz p x q por outra matriz q x r cujo algoritmo requer
O(pqr) operações. Seja o produto:

M = M1[20, 30] x M2[30, 10] x M3[10, 20] x M4[20, 50]

Com base no algoritmo estudado em aula, determine qual a sequência que resolve o
produto das matrizes com o menor número de operações.

34. Algoritmos criados para resolver um mesmo problema podem diferir de forma
drástica quanto a sua eficiência. Para evitar esse fato, são utilizadas técnicas
algorítmicas, isto é, conjunto de técnicas que compreendem os métodos de
codificação de algoritmos de forma a salientar a sua complexidade, levando-se em
conta a forma pela qual determinado algoritmo chega à solução desejada.

Considerando os diferentes paradigmas e técnicas de projeto de algoritmos, analise as


afirmações abaixo, indicando se são verdadeiras ou falsas.
Além disso, a cada afirmação falsa, indicar o trecho da frase que faz a afirmação
incorreta e reescreva a frase para que ela fique correta.

I. Um algoritmo guloso nem sempre faz escolhas que parecem ser as melhores no
momento, ou seja, escolhas ótimas locais acreditando que estas escolhas o
levem a uma solução ótima global. Por essa estratégia, nem sempre
asseguram-se soluções ótimas, mas, para muitos problemas, as soluções são
ótimas.
II. A técnica de tentativa e erro (Backtracking) efetua uma escolha ótima local, na
esperança de obter uma solução ótima global.
III. O uso de heurísticas (ou algoritmos aproximados) é caracterizado pela ação de
um procedimento chamar a si próprio direta ou indiretamente.
IV. A técnica de programação dinâmica decompõe o processo em um número
finito de subtarefas parciais que devem ser exploradas exaustivamente.
V. A técnica de divisão e conquista pode ser dividida em três etapas: dividir a
instância do problema em duas ou mais instâncias menores; resolver as
instâncias menores recursivamente; obter a solução para as instâncias originais
(maiores) por meio da combinação dessas soluções.

35. Uma heurística é um algoritmo que pode produzir um bom resultado, ou até
mesmo obter a solução ótima, mas pode também não produzir solução
alguma ou uma solução que está distante da solução ótima.
Considerando a heurística para o problema do Caixeiro Viajante em um
grafo:

1. Inicie em um vértice arbitrário.


2. Procure o vértice mais próximo do último vértice adicionado que não
esteja no caminho e adicione ao caminho a aresta que liga esses dois
vértices.
3. Quando todos os vértices estiverem no caminho, adicione uma aresta
conectando o vértice inicial e o último vértice adicionado.

Seja o grafo abaixo e a tabela que representa a distância entre seus pares de vértices.

5 1

4 2

Baseado na heurística apresentada e no grafo, pede-se:

a) Utilizando-se a heurística para o problema do caixeiro viajante, qual o caminho e o


seu comprimento encontrado para o caixeiro viajante?
b) Você pode afirmar que o caminho encontrado é ótimo? Por quê?

36. Questão sobre Problemas P, NP, NP-Completo.

Seja o algoritmo não determinista CaixeiroViajanteND(listaAdjacencia,


TotalDeVertices) que encontra o caminho a ser percorrido no grafo de TotalDeVertices
representado pela ListaDeAdjacencia, considerando a menor rota.

Módulo CaixeiroViajanteND(listaAdjacencia, TotalDeVertices)


Início
I  1;
para( t = 1; t <= TotalDeVertices; t++)
j  escolhe(i , listaAdjacencia);
antecessor[ j ] = i;
fim-para
Fim
Utilizando o algoritmo CaixeiroViajanteND, o problema da satisfabilidade e a teoria da
complexidade envolvendo a classe de problemas P, NP e NP-Completo. Assinale
VERDADEIRO ou FALSO nas afirmações a seguir. Além disso, para as afirmações
FALSAS destaque o que está incorreto.

( ) O problema que o algoritmo CaixeiroViajanteND resolve pertence a classe de


problemas P, o problema da satisfabilidade também possui um algoritmo não
determinista polinomial, mas este problema pertence a classe de problemas NP.
( ) Não existe algoritmo determinista polinomial para os problemas similares aos
que o algoritmo CaixeiroViajanteND resolve.
( ) Todos os problemas que somente podem ser resolvidos por um algoritmo não
determinista com complexidade polinomial pertencem a classe de problemas NP. Além
disso, os problemas mais “difíceis” de NP pertencem a classe de problemas NP-
Completo.
( ) Encontrando um algoritmo determinista polinomial para o problema da
satisfabilidade, podemos afirmar que a classe de problemas P é diferente de NP.
( ) Existem problemas que podem ser resolvidos por um algoritmo não
determinista com complexidade polinomial e que podem ser resolvidos por um
algoritmo determinista em tempo polinomial.
( ) Como foi provado que NP  P, o problema da satisfabilidade pertence a classe
de problemas NP.
( ) O algoritmo não determinista CaixeiroViajanteND tem complexidade
polinomial e é igual a O(n).
( ) Como P é diferente de NP, o problema da satisfabilidade pertence a classe de
problemas P ou a classe de problemas NP – P.
( ) A relação entre as classes de problemas P e NP representa o problema não
resolvido mais famoso em Ciência da Computação.

37. Considerando que um certo algoritmo forneceu a equação de recorrência abaixo:


T(n) = 3T(n/2) + n, n>1 e T(1) = 1
Determine:
a) A fórmula fechada de T(n) pelo método da substituição.

b) O O-grande desse algoritmo.

38. Dado um conjunto A = { a 1, a2, ..., an } de n inteiros, descreva um algoritmo ótimo


para calcular cada uma das somas parciais e armazenar em um vetor S de
tamanho n.
k
S k =∑ a i
i=1
para k = 1, 2, ..., n. (Pressuponha que os vetores são indexados a partir do 0). O
algoritmo ótimo tem T(n) = O(n).

39. Considere o programa a seguir em C:


int F2(int X, int Y) { int main()
#include <stdio.h> if (X < Y) {
int F1(int X, int Y) { return 0; int A, B;
if (X < Y) else scanf("%d %d",&A, &B);
return X; return 1 + F2(X-Y,Y); if ((A > 0) && (A < 1000)
else } && (B > 1) && (B < 10)) {
return F1(X-Y,Y); F3(A,B);
} void F3(int X, int Y) { printf("\n");
if (X < Y) }
printf("%d",X); return 0;
else { }
F3(F2(X,Y),Y); }
printf("%d",F1(X,Y));
}
}

No programa apresentado, a técnica da recursividade foi aplicada às três funções F1,


F2 e F3. Essa técnica envolve a definição de uma função ou rotina que pode invocar a si
própria. Com relação ao programa apresentado e à técnica de recursão, atribua F
(falso) ou V (verdadeiro) para as afirmativas a seguir.

( ) A chamada da função F1, através da expressão F1(X,Y), pode ser substituída,


sem alterar o resultado do programa, pela expressão X%Y .

( ) O objetivo da função F2 é retornar o valor da variável X elevado à Y-ésima


potência.

( ) A chamada à função F3 entrará em uma recursão sem fim se o valor da


variável X for maior que o valor da variável Y.

( ) A expressão ((A > 0) && (A < 1000) && (B > 1) && (B < 10)), da função main,
pode ser substituída pela expressão (!((A <= 0) || (A >= 1000) || (B <= 1) || (B >= 10))),
sem afetar o resultado do comando condicional if nesta expressão.

Além disso, considerando que A e B foram lidos pelo scanf com os respectivos valores
10 e 5. Determine o que será impresso na tela pelos printf.

40. Algoritmos criados para resolver um mesmo problema podem diferir de forma
drástica quanto a sua eficiência. Para evitar este fato, são utilizadas técnicas
algorítmicas, isto é, conjunto de técnicas que compreendem os métodos de
codificação de algoritmos de forma a salientar sua complexidade, levando-se em
conta a forma pela qual determinado algoritmo chega à solução desejada.

Considerando os diferentes paradigmas e técnicas de projeto de algoritmos, o


algoritmo abaixo:

Módulo OQueEuSou (A, i, f)


Início
Se (i = f) retorna i;
Senão
p  OqueEuSou (A, i, piso(( i+f)/2))
q  OqueEuSou (A, piso(( i+f)/2) + 1, f)
se A[p] <= A[q] retorna p
senão retorna q;
fim

Obs.: considere que n = f - i + 1 é o número de comparações entre os elementos de


um vetor A, numa execução de OQueEuSou( A, i, f).

I. O algoritmo OQueEuSou(n) retorna o índice do elemento máximo do vetor.


II. O algoritmo OQueEuSou(n) utiliza como técnica de programação a
especialização da técnica da divisão e conquista que procura sempre
manter o balanceamento na subdivisão de um problema em partes menores
e iguais.
III. O algoritmo OQueEuSou tem complexidade O(nlog2n).
IV. O algoritmo OQueEuSouNaoRec realiza a mesma funcionalidade que o
algoritmo OQueEuSou, mas não se utiliza da recursividade.

Módulo OQueEuSouNaoRec ( A, n )
início
posMax ¬ 0;
para (i ¬ 1; i £ n-1; i++) faça
se (A[posMax} < A[i]) então
posMax ¬ i
fim-se
retorne posMax;
fim

V. A complexidade do algoritmo OQueEuSouNaoRec é O(n).

a) Analise as afirmações acima, indicando se são verdadeiras ou falsas.


b) Além disso, a cada afirmação falsa, indicar o que faz a afirmação incorreta e corrija-
a para torná-la verdadeira.

41. a) Questão sobre Problemas P, NP, NP-Completo


Utilizando e a teoria da complexidade envolvendo a classe de problemas P, NP e
NP-Completo, preencha com V (Verdadeiro) ou F (Falso) as lacunas abaixo.
( ) Uma maneira de lidar com problemas de otimização que pertence a classe de
problemas NP-completo é utilizar a técnica de algoritmos aproximados. Somente
temos que ter em mente que a técnica de algoritmos aproximados poderá encontrar
uma boa solução, não necessariamente a ótima.
( ) Na Teoria da Complexidade, se um problema é considerado “fácil”, significa
que existe um algoritmo não-determinista polinomial que o resolve.
( ) O problema da satisfabilidade pertence a classe de problemas P se e somente
se P = NP.
( ) Não sabemos se P = NP ou P  NP, logo também não podemos dizer que
algoritmos deterministas são um caso especial de algoritmos não-deterministas.
( ) Os melhores algoritmos conhecidos para resolver problemas NP-Completo
tem um comportamento de pior caso que é exponencial no tamanho da entrada.

b) Questão sobre Paradigmas de Programação


Relacione a coluna da esquerda com a coluna da direita.
( ) O problema da mochila fracionária pode ser resolvido ( A ) Tentativa e
pela técnica que realiza uma sequencia de escolhas, que se Erro
inicia a partir de uma configuração bem sucedida e, então,
interativamente, escolhe a que parece ser a melhor do
conjunto de possíveis configurações.
( ) O problema da multiplicação de inteiros grandes pode (B)
ser resolvido pela técnica que envolve a solução de um Método/Algoritmo
problema computacional dividindo-o em um ou mais Guloso
subproblemas de tamanho menor, resolvendo cada
subproblema recursivamente, e então, “casando” a solução
dos subproblemas para produzir a solução do problema
original.
( ) O problema da mochila 0-1 tem complexidade O(nW) ( C ) Algoritmos
(onde n é o número de itens de um conjunto S e W é o peso Aproximados e
máximo que pode ser carregado na mochila) quando Heurísticas
resolvido pela técnica que aplica o princípio “Uma solução
não ótima de um subproblema não pode ser subsolução de
solução ótima do problema”.
( ) O problema do segmento de soma máxima de um ( D ) Divisão e
vetor A de tamanho n pode ser resolvido em um tempo (n) Conquista
pela técnica que constrói por etapas uma resposta ótima,
combinando respostas já obtidas para partes menores. Em
cada passo, sub-resultados são combinados dando respostas
para partes maiores até que se obtenha uma resposta para o
problema original. A decomposição é feita uma única vez, e
além disso, os casos menores são tratados antes dos
maiores.
( )( ) O problema da cobertura de vértices em um ( E ) Programação
grafo G é um problema NP-Completo tem uma solução que Dinâmica
não é ótima, utilizando-se esta técnica que encontra uma
boa solução combinando na sua resolução outra técnica que
constrói por etapas uma resposta ótima. Esta segunda
técnica, a cada passo, após selecionar um elemento de
entrada (o melhor), decide se é viável (vindo a fazer parte da
resposta ou não). Após uma sequencia de decisões,
buscando sempre pelo melhor elemento, uma solução para o
problema é encontrada.
( )( ) O problema de encontrar um ciclo de Hamilton
em um grafo é um problema NP-Completo. No entanto,
pode ser resolvido combinando-se uma técnica que encontra
uma possível solução com outra técnica que realiza uma
busca exaustiva em uma árvore de subtarefas fazendo-se
podas na árvore para resolver instâncias deste problema.

Você também pode gostar