Projeto e Análise de Algoritmos – Profa. Dr. Jerusa Marchi Lista de exercícios 1 Luiz Henrique Zambom Santana Parte 1 Capítulo 1 - Exercícios 1.1-1, 1.1-2, 1.1-3, 1.1-4, 1.1-5, 1.2-2, 1.2-3 Capítulo 2 - Exercícios 2.1-4, 2.2-2, 2.3-6 e Problema 2-2. 1.1-1. Give a real-world example that requires sorting or a real-world example that requires computing a convex hull. Um exemplo do mundo real que requer ordenação é organizar os candidatos de um concurso público de acordo com seu desempenho. Por outro lado, calcular um casco convexo pode ser necessário para aplicações em ferramentas CAD. 1.1-2. Other than speed, what other measures of efficiency might one use in a real-world setting? Outras exemplos de eficiencia de software no mundo real são segurança, facilidade de uso (userfriendness), escalabilidade e custo de desenvolvimento. 1.1-3. Select a data structure that you have seen previously, and discuss its strengths and limitations. A lista ligada linear possui como principal limitação a necessidade de se percorrer toda a lista para saber se um valor está presente entre seus elementos, a sua principal vantagem em relação à estruturas estáticas - como matrizes e vetores -, é o fato de que seu tamanho não precisa ser definido no momento de compilação dos programas que as usem, mas sim podem crescer o diminuir dinâmicamente durante a execução desse programa. 1.1-4. How are the shortest-path and traveling-salesman problems given above similar? How are they different? Ainda que ambos sejam problemas que possam ser modelados com grafos, o problema de menor caminho (SP) é apena uma parte do problema do caixeiro viajante (TSP). O problema do caixeiro viajante adiciona ao problema do menor caminho a necessidade de que cada ponto seja visitado exatamente uma vez e que se retorne ao ponto de início. Isso faz com que o segundo problema seja NPdifícil - ou seja, não se sabe se há uma solução que cresça em tempo polinomial para o mesmo. Isto porque, o problema do caixeiro viajante contém uma permutação de todos os nós do grafo de caminho, fazendo com que o espaço de busca do menor caminho aumente de forma exponencial. 1.1-5. Come up with a real-world problem in which only the best solution will do. Then come up with one in which a solution that is “approximately” the best is good enough. Um problema que envolva, por exemplo, calcular o saldo de uma conta bancária ao final de uma sequência de transações só é aceitável se oferecer a melhor solução (mais correta) possível. Por outro lado, o problema de previsão de temperatura para uma cidade aceita soluções que ofereçam resultados apenas próximos à temperatura verificada. 1.2-2. Suppose we are comparing implementations of insertion sort and merge sort on the same machine. For inputs of size n , insertion sort runs in 8n^2 steps, while merge sort runs in 64n lg n steps. For which values of n does insertion sort beat merge sort? A melhor forma de descrever esse problema é através da seguinte inequação: 8n^2< 64n lg n n< 8 lg n n/8< lg n 2^(n/8)<n 2^(n/8)-n<0 Assim, o insertion sort é melhor que o merge sort para os seguintes valores 2≤n≤43 1.2-3. What is the smallest value of n such that an algorithm whose running time is 100*n^2 runs faster than an algorithm whose running time is 2^n on the same machine? A melhor forma de descrever esse problema é através da seguinte inequação: 100*(n^2)<2^n log(100*n^2)<log(2^n) log100+log(n^2)<log(2^n) log100+2*logn<nlog2 2+2*log n < n*0.3010 Assim, o primeiro algoritmo é executado mais rapidamente a partir de n=15 2.1-4. Consider the problem of adding two n-bit binary integers, stored in two n-element arrays A and B. The sum of the two integers should be stored in binary form in an (n+1)-element array C. State the problem formally and write pseudocode for adding the two integers. Pseudocódigo: C ← [1 ... n + 1] // C está preenchido com zeros. for i ← 1 to n do sum ← A[i] + B[i] + C[i] C[i] ← sum % 2 C[i + 1] ← sum / 2 //divisão de inteiros output C 2.2-2. Consider sorting n numbers stored in array A by first finding the smallest element of A and exchanging it with the element in A[1]. Then find the second smallest element of A, and exchange it with A[2]. Continue in this manner for the first n-1 elements of A . Write pseudocode for this algorithm, which is known as selection sort . What loop invariant does this algorithm maintain? Why does it need to run for only the first n 1 elements, rather than for all n elements? Give the best-case and worst-case running times of selection sort in Ω notation. SELECTION-SORT(A) for i ← 1 to length(A) - 1 do key ← i //encontre o i-ésimo menor elemento de A for j ← i to length(A) do key2 ← j if A[key] > A[key2] then key ← key2 //troque o i-ésimo menor elemento e o i-ésimo elemento de A temp ← A[key] A[key] ← A[i] A[i] ← temp Loop invariante: No início da primeira iteração para o loop das linhas o sub-array A[1.. i-1] consiste dos menores elementos de A organizados de forma ordenada. O algoritmo só deve ser executado para os primeiros n-1 elementos, pois se o último elemento é menor que algum outro ele será trocado em alguma iteração. O melhor e o pior caso são Θ(n^2) porque o comprimento inteiro do vetor deve ser buscado para todo elemento do vetor, não importa a ordem inicial dos elementos. 2.3-6. Observe that the while loop of lines 5–7 of the INSERTION-SORT procedure in Section 2.1 uses a linear search to scan (backward) through the sorted subarray A[1.., j-1]. Can we use a binary search (see Exercise 2.3-5) instead to improve the overall worst-case running time of insertion sort to Ω (n lg n)? Essa modificação não ajudaria a diminuir a complexidade do algoritmo, pois, mesmo com a busca binária, ainda seria necessário mover elementos após cada inserção, o que faz com que o algoritmo continue Ω (n^2). Problema 2-2. Bubblesort is a popular, but inefficient, sorting algorithm. It works by repeatedly swapping adjacent elements that are out of order. (algoritmo omitido) a. Let [A] denote the output of BUBBLESORT(A). To prove that BUBBLESORT is correct, we need to prove that it terminates and that A'[1]≤A'[2]≤…≤A'[n] where n=length[A]. What else must be proved to show that BUBBLESORT actually sorts? Nós precisamos também provar que os elementos A' são apenas uma permutação dos elementos de A. b. State precisely a loop invariant for the for loop in lines 2-4, and prove that this loop invariant holds. Your proof should use the structure of the loop invariant proof presented in this chapter. O loop invariante para as linhas 2-4 pode ser definido da seguinte forma: o sub-array A[j..n] vai ter o menor elemento na primeira posição, sendo que esse sub-array será uma permutação de A original. • • Inicialização: inicialmente j=n, então A[j..n]=A[n], que está trivialmente consistente com o loop invariante. Manutenção: durante o loop invariante, A[j] é o menor elemento de A[j..n]. Se A[j]<A[j-1] ambos terão suas posições trocadas, que garante que A[j-1] é o menor elemento de A[j-1..n], o que mantem o loop invariante até a próxima iteração. • Fim: o loop irá terminar quando j=i, assim nesse momento A[i] será o menor elemento de A[i..n]. c. Using the termination condition of the loop invariant proved in part (b), state a loop invariant for the for loop in lines 1-4 that will allow you to prove inequality (2.3). Your proof should use the structure of the loop invariant proof presented in this chapter. O loop invariante para as linhas 1-4 pode ser definido da seguinte forma: o sub-array A[1..i-1] consiste dos elementos de A[1..n] ordenados, cada um desses elementos serão menores o iguais que a sub-array A[i..n] e esse array será apenas uma permutação do original. • • • Inicialização: inicialmente i=1, então A[1..i]=A[1], que está trivialmente consistente com o loop invariante. Manutenção: durante o loop invariante, A[1..i-1] está ordenado. Quando o loop interno termina, A[i] será o menor elemento de A[i..n], que significa que A[1..i] está ordenado, mantendo o loop invariante até a próxima iteração. Fim: o loop irá terminar quando i=n, assim nesse momento todo array A estará ordenados. d. What is the worst-case running time of bubblesort? How does it compare to the running time of insertion sort? O loop externo deve ser executado n vezes (ou seja, para todos elementos do array), enquanto o loop interno percorre todo o array uma vez, parte do array outras n-i vezes. O tempo de execução do bubbe sort é o mesmo do insert sort, ou seja Θ(n^2). Parte 2 Capítulo 3 - Problema 3-2 , 3-3 (a) Capítulo 4 - Exercícios 4.3-1, 4.3-2, 4.3-3, 4.3-6 (usando expansão telescópica) 4.4-1, 4.4-2, 4.4-3, 4.4-4, 4.4-5, 4.4-6, 4.4-7, 4.5-1, 4.5-3, 4.5-4, 4.5-5. Problema 3-2. Indicate, for each pair of expressions (A, B) in the table below, whether A is O, o, Ω, ω, Θ of B. Assume that k ≥ 1, > 0, and c > 1 are constants. Your answer should be in the form of the table with “yes” or “no” written in each box. A tabela fica da seguinte forma: A B O o Ω ω Θ lgkn n sim sim sim não não n^k n^c sim sim sim não não SQRT(n) n^(sin n) não não não não não 2^n 2^(n/2) não não sim sim não n^(lg c) c^(lg n) sim não sim não sim lg(n!) lg(n^n) sim não sim não sim Problema 3-3 (a). Rank the following functions by order of growth; that is, find an arrangement g1, g2, . . . , g30 of the functions satisfying g1 = Ω(g2), g2 = Ω(g3), . . . , g29 = Ω(g30). Partition your list into equivalence classes such that f(n) and g(n) are in the same class if and only if f(n) = Θ(g(n)). O ranqueamento das funções é: 2 n+1 > 22 n > (n+1)! > n! > en > n*2n > 2n > (3/2)n > nlg lg n e (lg n)lg n > (lg n)! > n3 > n2 e 4lg n > n lg n e lg(n!) > n e 2lg n > (√2)lg n > 2√2 lg n > lg2 n > ln n > √ lg n > ln ln n > 2lg* n > lg* (lg n) e lg* n > lg(lg* n) > 1 e n1/lg n 1/ lg n 4.3-1. Show that the solution of T(n)=T(n-1)+n is O(n^2) Iteração Expansão k=1: T(n)=T(n-1)+n k=2: Encontrar T(n-1): T(n-1)=T((n-1)-1)+(n-1) T(n-1)=T(n-2)+n-1 Substituir T(n-1) na equação anterior: T(n)=T(n-2)+n-1+n T(n)=T(n-2)+2n-1 k=3 Encontrar T(n-2): T(n-2)=T((n-2)-1)+(n-2) T(n-2)=T(n-3)+n-2 Substituir T(n-2) na equação anterior: T(n)=T(n-2)+2n-1 T(n)=T(n-3)+n-2+2n-1 T(n)=T(n-3)+3n-3 Generalizando para k T(n)=T(n-k)+(k)n -(k), assim vemos que O(n^2) é solução para T(n) 4.3-2. Show that the solution of T(n)=T(n/2)+1 is O(n^2) Resolvendo essa recorrência pelo método iterativo: Iteração Expansão k=1: T(n)=T(n/2)+1 k=2: Encontrar T(n/2): T(n/2)=T(n/4)+1 Substituir T(n/2) na equação anterior: T(n)=T(n/4)+2 k=3 Encontrar T(n/4): T(n/4)=T(n/8)+1 Substituir T(n/4) na equação anterior: T(n)=T(n/8)+3 Generalizando para k T(n)=T(n/2^k)+k, vemos que O(n^2) é solução para T(n) 4.3-3. We saw that the solution of 2T([n/2])+n is O (n lg n). Show that the solution of this recurrence is also Ω (n lg n). Conclude that the solution is Θ(n lg n). Primeiro supomos que T(n)≤cn lgn: T(n)≤2c⌊n/2⌋lg⌊n/2⌋+n ≤cn lg (n/2)+n ≤cn lg n−cnlg2+n ≤cn lg n+(1−c)n ≤cn lg n para c≥0 Depois testamos T(n)≥ c(n+2) * lg(n+2): T(n)≥2c*(⌊n/2⌋+2)*(lg(⌊n/2⌋+2)+n ≥2c*(n/2−1+2)*(lg(n/2−1+2)+n ≥2cn+22lgn+22+n ≥c*(n+2)*lg(n+2)−c(n+2)*lg2+n ≥c*(n+2)*lg(n+2)+(1−c)*n−2c, para n ≥ 2c/(1−c) ≥c(n+2)lg(n+2) Por isso, T(n) é Θ(n lg n). 4.3-6. Show that the solution of T(n)=2T([n/2]+17)+n is O(n lg n). Suponha que T(n)=2T([n/2]+17)+n para todos n e que T(n)=(n lg n) para n menos que algum limite superior k. Uma vez que T(n)=)(n lg n) para valores menors que k, então existe uma constante c tal que T(n)≤ cn lg n. Assim, T(⌊n/2⌋+17)≤c(⌊n/2⌋+17) lg(⌊n/2⌋+17). Portanto, T(n)≤2c(⌊n/2⌋+17) lg(⌊n/2⌋+17)+n, assim T(n)≤cn lg n. 4.4-1. Use a recursion tree to determine a good asymptotic upper bound on the recurrence T(n)=3T([n/2])+n. Use the substitution method to verify your answer. A árvore de recursão é a seguinte (um mesmo nível da árvore está em cada linha): Nível # nós #custo cn 3^0 n 3 x T(n/2) T(n/2)=3(T(n/4)+n/2 3^1 3^1*n/3=n 9 x T(n/4) T(n/4)=3(T(n/8)+n/4 3^2 3^2*n/9=n 3^n 3^h*n=1, onde h é a altura da árvore de recursão … T(1) Como no último nível o tamanho de n=1, temos que 3^h*n=1, por isso h=ln3 n, assim T(n)=3^h*n+SUM(n). Dessa forma, T(n)=nT(1)+n*lg3n, e Θ(n)=(n lgn). Pelo método de substituição supomos que T(n)≤cn^lg3+2n, então T(n)≤cn^lg3+2n ≤3c(n/2)^lg3+2n/2+n ≤cn^lg3+2n Assim, temos que T(n) é Θ(n^lg3) 4.4-2. Use a recursion tree to determine a good asymptotic upper bound on the recurrence T(n)=T(n/2)+n^2. Use the substitution method to verify your answer. A árvore de recursão é a seguinte (um mesmo nível da árvore está em cada linha). Nessa tabela, i significa um passo qualquer da recursão e h, a quantidade de passos para que n seja 1, ou seja a altura da árvore. Nível 0: c(n^2) 1: T(n/2) T(n/2)=T(n/4)+n^2/4 2: T(n/4) T(n/4)=T(n/8)+n^2/16 i: … T(n/2^i)=T(n/2^i)+n^2/2^i h: T(1) T(1)=1 Assim, T(n)=T(1)+SUM(n^2/2^i) T(n)=T(1)+(n^2)*SUM(1/2^i), dessa forma o somatório representa uma série geométrica e o valor T(n) final será T(n)=T(1)+(n^2). Do qual podemos afirmar que Θ(n) é n^2. Pelo método da substituição supomos que T(n)<=cn^2, então T(n)≤c(n/2)^2+n^2 ≤cn^2/4+n^2 ≤(c/4+1)n^2, (c>4/3) ≤cn^2 Assim, Θ(n) é n^2. 4.4-5. Use a recursion tree to determine a good asymptotic upper bound on the recurrence T(n)=T(n1)+T(n/2)+n. Use the substitution method to verify your answer. Supondo que A(n)=T(n/2)+n T(n)=T(n-1)+A(n)=T(n-2)+A(n-1)+A(n)=...=A(1)+A(2)+...+A(n) T(n)=sum[1..n]A(n) T(n)=sum[i=1..n]T(i/2)+sum[i=1..n]i assumindo que n/2 é uma divisão por inteiro, T(n/2)=T((n+1)/2) para um n par, então a primeira soma consiste de duas metades iguais: T(1)+T(1)+T(2)+T(2)+... T(n)=2*sum[1..n/2]T(i)+n*(n-1)/2, desde que T(n)<=T(m) para todo n<=m T(n)<=n*T(n/2)+n*(n-1)/2, pois T(n/2)>=n/2>=(n-1)/2 T(n)<=n*T(n/2)+n*T(n/2)=2*n*T(n/2), considerando apenas para n=2^k, n=2^k e U(k)=T(2^k) U(k)<=2*(2^k)*U(k-1)=2^(k+1)*U(k-1), se L(k)=log2 U(k) L(k)<=k+1+L(k-1), como nas etapas 1 e 2 L(k)<=k*(k-1)/2+k=k*k/2-k/2+k<=k*k U(k)=2^L(k)<=2^SQRT(k) T(n)=U(log2 n)<=2^SQRT(log2 n) 4.4-6. Argue that the solution to the recurrence T(n)=T(n/3)+T(2n/3)+cn, where c is a constant, is Ω(n lg n) by appealing to a recursion tree. O caminho mínimo para uma folha tem log 3n níveis, sendo que o custo para cada nível é cn. Se cortarmos a árvore exatamente abaixo da primeira folha, teremos complexidade cn*log 3n, que será Ω(n lg n). 4.5-1. Use the master method to give tight asymptotic bounds for the following recurrences. a. T(n) = 2T(n/4) + 1 Para essa recorrência temos a = 2, b = 4, f (n) = 1. Podemos aplicar o caso 1 do teorema para concluir que Θ(SQRT(n)). b. T(n) = 2T(n/4) +1 Para essa recorrência temos a = 2, b = 4, f (n) = SQRT(n). Podemos aplicar o caso 2 do teorema para concluir que Θ(SQRT(n) lg n). c. T(n) = 2T(n/4) + n Para essa recorrência temos a = 2, b = 4, f (n) = n. Podemos aplicar o caso 3 do teorema para concluir que Θ(n). d. T(n) = 2T(n/4) + n2 Para essa recorrência temos a = 2, b = 4, f (n) = n. Podemos aplicar o caso 3 do teorema para concluir que Θ(n^2). 4.5-3. Use the master method to show that the solution to the binary-search recurrence T(n)=T(n/2)+Θ(1) is T(n)=Θ(lg n). (See exercise 2.3-5 for a description of binary search). Podemos usar o caso 2 do teorema com a=1,b=2, então: f(n)=Θ(n^log21)=Θ(1) T(n)=Θ(lg n) 4.5-4. Can the master method be applied to the recurrence T(n)=4T(n/2)+n 2lg n? Why or why not? Give an asymptotic upper bound for this recurrence. Com a=4,b=2, nós temos f(n)=n2lg n ≠ O(n2−ϵ) ≠ Ω(n2−ϵ), por isso não podemos aplicar o teorea mestre. Para descobrir o limite assintótico, supomos Θ(n2 lg2 n): T(n)≤4T(n/2)+n2lgn ≤4c(n/2)2 lg2(n/2)+n2lg n ≤cn2lg(n/2)lgn−cn2lg(n/2)lg2+n2lgn ≤cn2lg2n−cn2 lg n lg2−cn2lg(n/2)+22lgn ≤cn2lg2n+(1−c) n2lg n−cn2lg(n/2), para c>1 ≤cn2lg2n−cn2lg (n/2) ≤cn2lg2n 4.5-5. Consider the regularity condition af(n/b)≥cf(n) for some constant c<1, which is part of case 3 of the master theorem. Give an example of constants a≥1 and b>1 and a function f(n) that satisfies all the conditions in case 3 of the master theorem, except the regularity condition. Se a=1, b=2, f(n)=n(2−cos n) Assim, se provamos: n/2*(2−cosn2)<cn (1−cos(n/2))/2<c c≥1−(cos(n/2))/2 MIN(cos(n/2))=−1 implica que c≥3/2. Porém, c<1. Parte 3 Capítulo 2 - Problema 2-4 Capítulo 4 - Exercícios 4.1-5, 4.2-1, 4.2-7, 4.5-2, Problema 4-5 Capítulo 16 - Exercícios 16.1-2, 16.1-3, 16.1-5. Problema 2-4 Inversions Let A[1..n] be an array of n distinct numbers. If i < j and A[i] > A[j] , then the pair (i,j) is called an inversion of A. a. List the five inversions of the array (2, 3, 8, 6, 1). (0, 4), (1, 4), (2, 3), (2, 4), (3, 4) b. What array with elements from the set {1,2,..,n} has the most inversions? How many does it have? O array na ordem inversa, assim todos pares (ou seja, n) do conjunto estarão contidos nesse array. c. What is the relationship between the running time of insertion sort and the number of inversions in the input array? Justify your answer. O insertion sort tem como principal argumento a troca de inversões adjacentes. d. Give an algorithm that determines the number of inversions in any permutation on n elements in ‚.n lg n/ worst-case time. (Hint: Modify merge sort.) Podemos modificar o merge sort e, da mesma forma que o algoritmo original, ele vai ter tempo n lg n no pior caso. MERGE_SORT(A, p, r): if p < r then inversoes ← 0 q ← (p + r) / 2 inversoes ← inversoes + MERGE_SORT(A, p, q) inversoes ← inversoes + MERGE_SORT(A, q + 1, r) inversoes ← inversoes + MERGE_SORT(A, p, q, r) merge_sort ← inversoes eles then merge_sort ← 0 4.1-5. Use the following ideas to develop a nonrecursive, linear-time algorithm for the maximumsubarray problem. MAX_SUBARRAY(A, n): sum ← 0, max_sum ← -INF; for i ← 1 to n do sum ← sum + A[i] if sum > max_sum then max_sum ← sum if sum < 0 then sum ← 0; MAX_SUBARRAY ← max_sum 4.2-1. Use Strassen’s algorithm to compute the matrix product (matriz omitida) S1=6, S2=4, S3=12, S4=−2, S5=5, S6=8, S7=−2, S8=6, S9=−6 e S10=14 P1=1*6=6 P2=4*2=8 P3=6*12=72 P4=(−2)*5=−10 P5=6*8=48 P6=(−2)*6=−12 P7=(−6)*14=−84 Assim, C11=48+(−10)−8+(−12)=18 C12=6+8=14 C21=72+(−10)=62 C22=48+6−72−(−84)=66 4.2-7. Show how to multiply the complex numbers a+bi and c+di using only three multiplications of real numbers. The algorithm should take a, b, c and d as input and produce the real component ac−bd and the imaginary component ad+bc separately. Usando o método de Karatsuba, fazemos S1=ac, S2=bd, e S3=(a+b)(c+d). Com isso, podemos computar: A=S1−S2 B=S3−S1−S2 Assim, o resultado final é A+Bi. 4.5-2. Professor Caesar wishes to develop a matrix-multiplication algorithm that is asymptotically faster than Strassen's algorithm. His algorithm will use the divide-and-conquer method, dividing each matrix into pieces of size n/4×n/4, and the divide and combine steps together will take Θ(n2) time. He needs to determine how many subproblems his algorithm has to create in order to beat Strassen's algorithm. If his algorithm creates a subproblems, then the recurrence for the running time T(n) becomes T(n)=aT(n/4)+Θ(n2). What is the largest integer value of a for which Professor Caesar's algorithm would be asymptotically faster than Strassen's algorithm? Para estar no terceiro caso do teorema mestre, devemos ter a<16. Nesse caso, o algoritmo será T(n)=Θ(n2). Para o segundo caso, com a=16, T(n)=Θ(n2logn). No primeiro caso do teorema mestre, para ser mais rápido que o algoritmo de Strassen, necessitamos log4a<log27, que será a<72=49. Assim, o maior valor inteiro será 48. Problema 4-5. Chip testing - Professor Diogenes has n supposedly identical integrated-circuit chips that in principle are capable of testing each other. The professor’s test jig accommodates two chips at a time. When the jig is loaded, each chip tests the other and reports whether it is good or bad. A good chip always reports accurately whether the other chip is good or bad, but the professor cannot trust the answer of a bad chip. a. Seja b o número de chips bons e nb ser o número de chips ruins. A partir deste pressuposto,sempre encontrar um conjunto B de bons chips e um conjunto R de chips ruins de tamanho igual ao de B. Agora, supondo que o conjunto R de chips ruins confunda o professor da seguinte forma: para qualquer teste, eles se declaram bons e os chips em B como ruins. Observe que os chips do conjunto B exibem um comportamento simétrico: eles se declaram bons e os chips em R como ruins. Isto implica que qualquer estratégia baseada na análise feita pelo professor, o comportamento dos chips em G será indistinguível do comportamento dos chips em B, isto é, esse comportamento não permite ao professor para determinar quais chips são bons. b. Dividimos os chips em dois grupos e os comparando par-a-par. Descartamos o par se tem como saída que apenas um dos chips é ruim, caso contrário (ou seja, se os dois reportam a mesma saída), guardamos os chips no conjunto de solução. Ao final, teremos que provar no máximo metade do conjunto total n, já que existem mais chips bons que ruins. c. Se, pelo menos, n/2 dos chips são bons, utilizando a resposta à questão b), podemos encontrar um chip bom. Agora, a fim de encontrar todos chips bons, nós podemos apenas testar o primeiro chip bom com todos os outros: para cada par, se pelo menos, um dos dois chips é bom será suficiente para decidir se o outro chip é bom ou não. Esta etapa demanda n-1 testes. Além disso, a fim de provar que os chips podem ser encontrados com Θ(n) testes par-a-par, só precisamos de mostrar que o número de testes para encontrar um chip é Θ(n). Para mostrar isso, podemos escrever a número de testes T(n)≤T([n/2])+[n/2]; e T(1)=0. A solução para este recorrência é T(n)=O(n) e pode ser calculado, por exemplo, argumentando por indução que T(n)≤2^(log n). 16.1-2. Suppose that instead of always selecting the first activity to finish, we instead select the last activity to start that is compatible with all previously selected activities. Describe how this approach is a greedy algorithm, and prove that it yields an optimal solution. A abordagem proposta é também um algoritmo guloso, pois recebe-se um conjunto de atividades S = {a1, a2, . . . , an}, onde ai = [Si , fi), e deve-se encontrar uma solução ótima ao selecionar a últma atividade que será iniciada que seja compatível com todas atividades selecionadas anteiormente. No lugar disso, vamos criar um conjunto S’={a1’, a2’ , . . . , an’}, onde ai’ = [ fi , si ), ou seja, S´é o inverso de S. Claramnte, um subconjunto {ai1 , ai2 , . . . , aik } ⊆ S é compaível, se e somente se o subconjunto também é compatível { a1 ’ , a2 ’ , . . . , ak ’ } ⊆ S ’. Assim, uma solução ótima em S também é um solução ótima em S´e vice e versa. Por isso, o algoritmo guloso apresentado no texto retorna o mesmo resultado ótimo quando executado em S´. 16.1-3. Not just any greedy approach to the activity-selection problem produces a maximum-size set of mutually compatible activities. Give an example to show that the approach of selecting the activity of least duration from among those that are compatible with previously selected activities does not work. Do the same for the approaches of always selecting the compatible activity that overlaps the fewest other remaining activities and always selecting the compatible remaining activity with the earliest start time. Existem três casos nessa pergunta, provar que: 1 – erro ao selecionar a atividade de menor duração; 2 – erro ao selecionar a atividade com menor interseccção; e 3 – erro ao selecionar a atividade com início mais cedo. O caso 1 está incorreto pois podemos escolher atividades que tenham uma duração muito pequena, mas que causem um intervalo muito grande para as atividades anteriores e posteriores, por isso, devemos também considerar seu tempo de início e sua intersecção com outras atividades. O caso 2 está incorreto pois considerando apenas a quantidade de intersecções, poderiamos desconsiderar duas (ou mais) atividades que estivesem perfeitamente encaixadas, mas que tivesse um grande número de interseções com outras atividades não ótimas; finalmente, o caso 3 está incorreto pois levando em consideração apenas o tempo de início, podemos errar ao escolher uma atividade que incia muito cedo, mas que dura um tempo tão grande que impeça a escolha de outras atividades.