1ª Lista de exercícios 1.1 Responder se é certo ou errado: Todo procedimento recursivo deve incorporar terminações sem chamadas recursivas, caso contrário ele seria executado um número infinito de vezes. 1.2 Responder se é certa ou errada cada afirmativa abaixo: (i) (ii) O algoritmo que calcula o fatorial de forma recursiva requer apenas uma quantidade constante de memória. O algoritmo abaixo requer o armazenamento do vetor fat, com n+1 elementos. fat[0] = 1 for(j = 1; j <= n; j = j+1) fat[j] = j * fat[j-1]; 1.3 Desenvolver um algoritmo não recursivo para o cálculo do fatorial de inteiro n ≥ 0, de tal forma que prescinda do armazenamento de qualquer vetor. 1.4 Mostrar que o algoritmo para o problema das Torres de Hanói, requer exatamente 2n-1 movimentos de disco para terminar. 1.5 Reescrever o algoritmo do problema das Torres de Hanói, de forma que a recursividade pare no nível correspondente a n = 1, e não a n = 0, como no algoritmo do texto. Há alguma vantagem em realizar essa modificação? Qual? 1.6 Elaborar um algoritmo não recursivo para o problema das Torres de Hanói. 1.7 Considere a seguinte generalização do problema das Torres de Hanói: O problema, agora, consiste em n discos de tamanhos distintos e quatro pinos, respectivamente, o de origem, o de destino e dois pinos de trabalho. De resto, o problema é como no caso de três pinos. Isto é, de início, os discos se encontram todos no pino-origem, em ordem decrescente de tamanho, de baixo para cima. O objetivo é empilhar todos os discos no pino-destino, satisfazendo às mesmas condições do caso dos três pinos. Elaborar um algoritmo para resolver essa generalização. Determinar o número de movimentos de disco efetuados. 1.8 Escrever as seguintes funções em notação O: n3 - 1 n2 + 2 log n 3nn + 5.2n (n - l)n + nn-1 302 1.9 A seqüência de Fibonacci é uma seqüência de elementos f1,···, fn, definida do seguinte modo: f1 = 0, f2 = 1, fj = fj-1 + fj-2, j > 2. Elaborar um algoritmo, não recursivo, para determinar o elemento fn da seqüência, cuja complexidade seja linear em n. 1.10 Determinar a quantidade de chamadas recursivas do seguinte algoritmo para determinar o elemento fn da seqüência de Fibonacci. int f (int n) { if (n == 1) return 0; else if (n ==2) return 1; else return (f(n - 1) + f(n - 2)); } 1.11 Considere a seguinte seqüência de elementos gl, ... , gn para um dado valor de k. gj = j - 1, 1 ≤ j ≤ k; gj = gj-l + gj-2, j > k. Elaborar um algoritmo para determinar o elemento gn da seqüência, cuja complexidade seja O(n). 1.12 Determine a complexidade dos algoritmos abaixo, justificando sua resposta: a) int MAIOR (int N, int A[]) { int i, max = A[0]; for (i=1; i<N, i++) if (max < A[i]) max = A[i]; return max; } b) void ORDENA (int N, int A[]) { int i; for(i=0; i<N-1; i++) for(j=0; j<N-1-i; j++) if (A[j] > A[j+1]) { x = A[j]; A[j] = A[j+1]; A[j+1] = x; } } c) n = 0; while (n < 10) { k = 1; while ( k < 10 ) { ... k = k + 1; } n = n + 1; } 1.13) Dois algoritmos A e B possuem complexidade n5 e 2n, respectivamente. Você utilizaria o algoritmo B ao invés do A. Em qual caso? Exemplifique. 1.14) Uma métrica utilizada para avaliar algoritmos é a Métrica Empírica. Essa consiste em escolher uma métrica (tempo, número de instruções executadas etc.), propor entradas diferenciadas (geralmente com alguma característica predefinida), ou seja, amostras. Finalmente executar o algoritmo com as entradas e analisar os resultados. Esta medida pode ser utilizada para comparar dois algoritmos. Critique a métrica. 1.15) Podemos dizer que um algoritmo com complexidade f(n) = O(f(n/2))? Justifique. 1.16) Considere o problema de encontrar um elemento em um conjunto ordenado de dados: a1 < a2 < a3 < ....< an. Elabore um algoritmo eficiente para este problema. Em que situações o algoritmo é ótimo? Em que situações o algoritmo apresenta o pior desempenho? Apresente um limite superior para este problema em função de n e exemplifique.