exercícios - moodle usp: e-disciplinas · 2017-04-08 · ... o algoritmo pode falhar quando ambos...

23
Lista 1 - PMR3201 Fabio G. Cozman, Thiago Martins 2017 Exercícios Nota: Exercícios marcados com * têm solução no final da lista. 1. Qual String é impressa pelo programa: def f(x): x = 2 x = 0 f(x) print (x) 2. (*) Escreva uma função em Python que receba dois arranjos, a e b, de tamanho igual, contendo números e retorne o produto interno de a e b = a i b i . Mostre que seu algoritmo está correto. 3. (*) O algoritmo de Mínimo Divisor Comum Binário 1 é um algoritmo alternativo ao tradicional algoritmo de Euclides. Ele tira proveito do fato de que computadores digitais binários podem rapidamente realizar operações de divisão por 2 através de um simples deslocamento de bits. Seu funcionamento, para dois números ímpares, pode ser descrito da seguinte maneira: Subtraia o menor número do maior. Enquanto o resultado for par, divida o resultado por 2. Substitua o maior número pelo resultado. Continue com o processo até obter dois números iguais. O maior denominador comum é o número final. Por exemplo, tome 145 e 25. Subtraindo-se 25 de 145 o resultado é 120. 120 é par, divide-se por 2, chegando a 60. 60 é par, divide-se por 2, chegando a 30. 30 é par, divide-se por 2, chegando a 15. O algoritmo prossegue com 25 e 15. Subtraindo-se 15 de 25 chega-se a 10. 10 é par, divide-se por 2, chegando a 5. O algoritmo prossegue com 15 e 5. Subtraindo-se 5 de 15 chega-se a 10. 10 é par, divide-se por 2, chegando a 5. O algoritmo para em 5 e 5. O maior divisor comum é 5 (verifique!). a) Escreva uma implementação em Python do algoritmo de Mínimo Divisor Comum binário para dois inteiros maiores do que zero ímpares. b) Mostre que o algoritmo termina em tempo finito. c) Mostre que o algoritmo é correto, ou seja, para dois inteiros maiores do que zero ímpares o algoritmo retorna o maior divisor comum. Sugestão: Observe que se a>b então gcd(a, b)= gcd(a - b, b). Além disso, se a é par e b não, então gcd(a, b)= gcd(a/2,b) d) Mostre que algoritmo ainda funciona quando somente um dos números é par. Sugestão: Divida o problema em dois casos, o caso em que o maior número é par e o caso em que o menor número é par. Mostre que para ambos os casos o algoritmo após algumas iterações passa a trabalhar com dois números ímpares. e) O algoritmo pode falhar quando ambos os números são pares (verifique!). Você é capaz de escrever uma modificação deste algoritmo que trabalhe também com dois números pares? Sugestão: Verifique que se ambos a e b são pares, então gcd(a, b)=2 · gcd(a/2, b/2) 1 Stein, J. (1967), "Computational problems associated with Racah algebra", Journal of Computational Physics 1 (3): 397–405 1

Upload: nguyenminh

Post on 13-Nov-2018

220 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

Lista 1 - PMR3201

Fabio G. Cozman, Thiago Martins

2017

ExercíciosNota: Exercícios marcados com * têm solução no final da lista.

1. Qual String é impressa pelo programa:

def f ( x ) :x = 2

x = 0f ( x )p r i n t ( x )

2. (*) Escreva uma função em Python que receba dois arranjos, a e b, de tamanho igual, contendo números eretorne o produto interno de a e b =

∑aibi. Mostre que seu algoritmo está correto.

3. (*) O algoritmo de Mínimo Divisor Comum Binário1 é um algoritmo alternativo ao tradicional algoritmode Euclides. Ele tira proveito do fato de que computadores digitais binários podem rapidamente realizaroperações de divisão por 2 através de um simples deslocamento de bits. Seu funcionamento, para doisnúmeros ímpares, pode ser descrito da seguinte maneira: Subtraia o menor número do maior. Enquantoo resultado for par, divida o resultado por 2. Substitua o maior número pelo resultado. Continue com oprocesso até obter dois números iguais. O maior denominador comum é o número final. Por exemplo, tome145 e 25. Subtraindo-se 25 de 145 o resultado é 120. 120 é par, divide-se por 2, chegando a 60. 60 é par,divide-se por 2, chegando a 30. 30 é par, divide-se por 2, chegando a 15. O algoritmo prossegue com 25 e15. Subtraindo-se 15 de 25 chega-se a 10. 10 é par, divide-se por 2, chegando a 5. O algoritmo prosseguecom 15 e 5. Subtraindo-se 5 de 15 chega-se a 10. 10 é par, divide-se por 2, chegando a 5. O algoritmo paraem 5 e 5. O maior divisor comum é 5 (verifique!).

a) Escreva uma implementação em Python do algoritmo de Mínimo Divisor Comum binário para doisinteiros maiores do que zero ímpares.

b) Mostre que o algoritmo termina em tempo finito.

c) Mostre que o algoritmo é correto, ou seja, para dois inteiros maiores do que zero ímpares o algoritmoretorna o maior divisor comum.Sugestão: Observe que se a > b então gcd(a, b) = gcd(a − b, b). Além disso, se a é par e b não, entãogcd(a, b) = gcd(a/2, b)

d) Mostre que algoritmo ainda funciona quando somente um dos números é par.Sugestão: Divida o problema em dois casos, o caso em que o maior número é par e o caso em queo menor número é par. Mostre que para ambos os casos o algoritmo após algumas iterações passa atrabalhar com dois números ímpares.

e) O algoritmo pode falhar quando ambos os números são pares (verifique!). Você é capaz de escrever umamodificação deste algoritmo que trabalhe também com dois números pares?Sugestão: Verifique que se ambos a e b são pares, então gcd(a, b) = 2 · gcd(a/2, b/2)

1Stein, J. (1967), "Computational problems associated with Racah algebra", Journal of Computational Physics 1 (3): 397–405

1

Page 2: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

4. Elabore um programa recursivo que calcule o Mínimo Divisor Comum de dois inteiros usando o algoritmotradicional de Euclides: Divida o número maior pelo menor e pegue o resto; então divida o divisor peloresto e assim sucessivamente até que o resto seja zero — o quociente da última divisão é o divisor comum.Por exemplo, tome 928 e 100: dividimos 928 por 100, obtemos resto 28; dividimos 100 por 28, obtemosresto 16; dividimos 28 por 16, obtemos resto 12; dividimos 16 por 12, obtemos resto 4; dividimos 12 por 4e obtemos resto zero — o resultado é 4.

5. (*) (Adaptado da PSUB-2015) O algoritmo de Euclides Extendido é um dos algoritmos necessários paraa geração de chaves de criptografia RSA. Como o nome sugere, ele é uma extensão do clássico algoritmode Euclides para calcular o máximo divisor comum. Além de calcular, como o algoritmo de Euclides, omáximo divisor comum r de a e b, ele também calcula um par de inteiros x, y tal que:

r = ax+ by

A listagem a seguir mostra uma implementação do Algoritmo de Euclides Extendido. Ela retorna a tuplar, x, y.

1 def egcd ( a , b ) :2 xa , ya = 1 , 03 xb , yb = 0 , 14 whi le b !=0 :5 q = a / / b # Q u o c i e n t e6 r = a − q ∗ b # R e s t o7 a = b ;8 b = r ;9 xa , xb = xb , xa − q ∗ xb

10 ya , yb = yb , ya − q ∗ yb11 re turn a , xa , ya

Este algoritmo supõe sempre que a > b. Seja ai, bi, xai, yai, xbi, ybi os valores das variáveis a, b, xa,ya, xb, yb ao final da i-gésima iteração do laco iniciado na linha 4, e a0 ,b0 , xa0, ya0, xb0, yb0 os valoresdestas variáveis antes da entrada no laço. Da análise do Algoritmo de Euclides tradicional feita em sala sãoconhecidos os seguintes fatos:

• O algoritmo termina em tempo finito (note que o controle de fluxo deste algoritmo é idêntico aoalgoritmo convencional).

• gcd (a0, b0) = gcd (ai, bi).

• bn = 0⇒ gcd (a0, b0) = an

Dado o exposto acima, demonstre que a implementação do algoritmo de Euclides Extendido está correta.

Sugestão: Mostre como vale em toda iteração

ai = xaia0 + yaib0

bi = xbia0 + ybib0

6. (*) (Adaptado da P1 2015) Considere o código abaixo para calcular a exponenciação xa:

1 def exp ( x , a ) :2 r = 13 whi le a ! = 0 :4 i f ( a %2)!=0: # V e r d a d e i r o se a impar5 r ∗= x6 a −= 17 a / / = 28 x = x∗x9 re turn r

Para este algoritmo são relevantes as seguintes propriedades da exponenciação:

• Se a é par então xa =(x2)ba/2c

• Para a positivo vale xa = x · xa−1

Page 2

Page 3: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

a) Moste que o algoritmo termina em tempo finito para a não-negativo.

b) Mostre que o algoritmo acima efetivamente retorna xa (sugestão: Considere como varia a cada iteraçãoo valor de r · xa após a execução da linha 8).

7. (*) (PREC 2015) Considere o código abaixo para converter um inteiro maior do que zero em uma Stringcom sua representação decimal:

1 def c o n v e r t ( x ) :2 r = " "3 whi le ( x ! = 0 ) :4 d = x % 105 # A d i c i o n a o d i g i t o de d6 # a e s q u e r d a de r7 r = chr ( ord ( ’ 0 ’ ) + d ) + r8 x / / = 109 re turn r

a) Mostre que o algoritmo termina em tempo finito para x maior do que zero.

b) Mostre que o algoritmo acima está correto, ou seja, ele efetivamente retorna a representação decimal dex.Sugestão: seja i o número da iteração do laço interno. Considere ao final de cada iteração do laço osvalores do número representado pela String armazenada em r e de x · 10i.

8. (*)(Adaptada da P1-2015) O produto de duas matrizes A = X · Y quadradas n× n é definido como:

Ai,j =

n∑k=1

Xi,kYk,j

Em Python, matrizes podem ser representadas por listas de linhas, as linhas por sua vez, listas de pontosflutuantes. Assim, por exemplo, se a variável a é uma referência a uma matriz A, então o elemento Ai,jpode ser acessado por a[i][j].

a) Com a representação acima, escreva uma função em Python que recebe 3 matrizes quadradas, x, y e ade tamanhos idênticos. A função deve escrever na matriz a o resultado do produto matricial de x e y.Use a seguinte assinatura:def matrixmult(x, y, a):

b) Escreva em função de N , onde N é o número de linhas/colunas das matrizes quadradas, a ordem decomplexidade da função escrita.

9. Escreva um algoritmo recursivo que transforme um número inteiro decimal em um número binário.

10. Considere a função f(n) definida recursivamente como segue: f(0) = 0; f(n) = f(n/2) se n é par;f(n) = 1 + f(n− 1) se n é ímpar. Codifique essa função em Python e obtenha o valor de f(100).

11. Considere o seguinte algoritmo:

def e x e r c i c i o 1 ( x ) :i f x < 5 :

re turn 3∗xe l s e :

re turn 2∗ e x e r c i c i o 1 ( x−5) + 7

Qual é o resultado de exercicio1(4) e exercicio1(20)? Desenhe a árvore de chamadas recursivaspara cada caso.

12. Dado o fragmento de código abaixo, desenhe a árvore de recursão para f(1, 10) e obtenha o valor de retorno.

def f ( x , y ) :i f x >= y :

re turn ( x+y ) / 2e l s e :

re turn f ( f ( x +2 , y−1) , f ( x +1 , y−2))

Page 3

Page 4: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

13. Coloque em ordem crescente de complexidade: O (2n), O (n!), O(n5), O (n log n). Qual é a complexi-

dade em notação BigOh de um programa que utiliza 3n4 + n log n operações?

14. Considere um polinômio p(x) =∑Ni=0 aix

i, e suponha que o valor desse polinômio para um particularvalor x é calculado usando o método de Horner:

p(x) = a0 + x(a1 + x(a2 + x(a3 + · · ·+ x(an−1 + xan) . . . ).

Caracterize em notação BigOh o número de operações aritméticas (adições e multiplicações) executadasnesse método.

15. Escreva uma rotina recursiva que resolve com custo O(2N)

o seguinte problema: Dado um conjunto de Ninteiros A1 a AN , e um inteiroK maior que todos os Ai, descubra se existe um subconjunto dos inteiros A1

a AN cuja soma é exatamente K. (Nota: Esse problema é chamado Problema da Soma de Subconjuntos;não existe nenhuma solução conhecida para esse problema que seja polinomial em N . A descoberta de umasolução polinomial para esse problema é um dos problemas abertos mais importantes em matemática, e oproblema mais importante em computação teórica.)

16. Considere a sequência: [26,34,9,0,4,89,6,15,27,44]. Desenhe esquematicamente os passos realizados porordenação por inserção e por união (mergesort) para ordenar essa sequência de forma crescente.

17. (*) (PREC 2015) O código a seguir mostra uma implementação em java do algoritmo Bubblesort paraordenação em ordem crescente de vetores de inteiros:

1 def b u b b l e s o r t ( x ) :2 u l t i m o = l e n ( x)−13 whi le u l t i m o > 0 :4 u l t i m o _ a l t e r a d o = 05 f o r j in range ( 1 , u l t i m o + 1 ) :6 i f x [ j ] < x [ j −1]:7 temp = x [ j ]8 x [ j ] = x [ j −1]9 x [ j −1] = temp

10 u l t i m o _ a l t e r a d o = j11 u l t i m o = u l t i m o _ a l t e r a d o − 1 ;

O princípio do algoritmo é comparar a ordem relativa de elementos contíguos em um vetor e realizar a trocade posição sempre que necessário. Note que ao final do laço interno, todos os elementos entre as posiçõesapontadas por ultimo e ultimo_alterado estão em ordem crescente e são maiores ou iguais a todosos elementos que os precedem. Como ultimo é inicializado com a última posição do vetor, e a cadaiteração do laço externo é modificado para a posição anterior a ultimo_alterado, o algoritmo terminaem tempo finito e ordena efetivamente o vetor.

a) Calcule em notação Big Oh a ordem de complexidade do algoritmo Bubblesort no seu pior caso.

b) Calcule em notação Big Oh a ordem de complexidade do algoritmo Bubblesort no seu melhor caso.

18. Qual é a ordem de complexidade em notação BigOh para ordenamento por inserção, seleção, união (mer-gesort) nos seguintes casos:

• O arranjo a ser ordenado está ordenado em ordem crescente.

• O arranjo a ser ordenado está ordenado em ordem decrescente.

Considere que o resultado final deve ser o arranjo ordenado em ordem crescente.

19. Escreva uma função que faça ordenamento de quatro inteiros distintos com no máximo cinco comparações.

20. (*)Prove que o seguinte algoritmo ordena corretamente um arranjo a entre índices i e j (inclusive), eobtenha a complexidade do algoritmo em notação BigOh.

Page 4

Page 5: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

1 def o rd en a ( a , i , j ) :2 i f a [ i ] > a [ j ] :3 a [ i ] , a [ j ] = a [ j ] , a [ i ]4 i f ( i +1) >= j :5 re turn6 k = ( j−i + 1 ) / / 37 o r de na ( a , i , j−k )8 o r de na ( a , i +k , j )9 o r de na ( a , i , j−k )

21. Considere o método:

1 def prova ( a , b , c ) :2 s = B i n a r y S e a r c h ( a )3 i = s . s e a r c h ( c )4 f o r j in range ( l e n ( a ) :5 f o r j in range ( l e n ( b ) ) :6 p r i n t ( j + s . s e a r c h ( b [ k ] ) )

onde BinarySearch é uma classe pública que executa busca binária em arranjos; o construtor de BinarySearchrecebe uma sequência de inteiros e o método público search(c) procura o inteiro c no arranjo, retor-nando o índice de c no arranjo. Suponha que c e que todos os elementos de b sempre estão em a. Considereque a e b podem ter tamanho N e no pior caso os dois tem tamanho N.

(a) Qual a complexidade do programa em notação BigOh no pior caso? Justifique.

(b) Suponha que a terceira linha seja removida; qual a complexidade do programa resultante em notaçãoBigOh, no pior caso? Justifique.

(c) Suponha que a sexta linha seja substituída porprint( j + k ). Qual a complexidade do programa resultante em notação BigOh no pior caso?Justifique.

(d) Suponha que a quarta e quinta linhas sejam substituídas por

f o r j in range ( i , l e n ( a ) ) :f o r k in range ( j , l e n ( b ) ) :

Qual a complexidade do programa resultante em notação BigOh no pior caso? Justifique.

22. Considere o código abaixo, assumindo que n é maior que zero:

1 def e x e r c i c i o 1 ( n , x ) :2 sum = 03 i f x < 0 : re turn −14 i f x >= n : x = n5 f o r i in range ( n ) :6 sum += 17 f o r j in range ( n ) :8 a u x i l i a r ( sum , n )9 f o r k in range ( j , n∗x ) :

10 sum += 211 re turn sum1213 def a u x i l i a r ( sum , n ) :14 sum = n ∗ sum

(a) Obtenha o valor de retorno da função exercicio1 em termos de n e x. Justifique.

(b) Obtenha a complexidade em notação BigOh em função apenas de n no pior caso. Justifique.

(c) Apresente esquematicamente (através de um desenho) o conteúdo do Stack e do Heap do programa aofim da primeira execução da linha 6, assumindo que tanto Stack quanto Heap estão vazios na chamadade exercicio1(10,1).

Page 5

Page 6: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

(d) Suponha que a linha 5 seja substituída pela linha

f o r i in range ( x , n ) :

Obtenha o valor de retorno em função de n e x; assumindo que n é par, obtenha a complexidade emnotação BigOh em função apenas de n no pior caso. Justifique. [1.5]

23. Considere o código abaixo:

1 def e x e r c i c i o 2 ( a , x , y ) :2 n = y−x3 i f n < 2 : re turn 04 z = 05 f o r i in range ( 7 ) :6 o r d e n a _ i n s e r c a o ( a , i ∗ n / / 7 , ( i +1) ∗ ( n / / 7 ) − 1)7 z = z + e x e r c i c i o 2 ( a , i ∗ n / / 7 , ( i +1) ∗ ( n / / 7 ) − 1)8 re turn z

A função ordena_insercao(a, x, y) ordena a sub-sequência de a entre indices x e y (inclusive)por inserção. Para simplificar, assuma que n é uma potência de um número que for apropriado.

(a) Apresente uma relação de recorrência que rege o custo T (n) desta função em termos do comprimenton do arranjo de entrada. Justifique.

(b) Resolva a relação de recorrência obtida no item anterior, justificando cada passo.

(c) Suponha que a linha 9 seja substuída por ordenação por união. Qual é a relação de recorrência resul-tante? Justifique.

24. Considere uma busca sequencial de um elemento X em um arranjo de N elementos. Normalmente assumi-mos que cada comparação utilizada na busca tem um custo fixo. Suponha porém que cada comparação exijauma busca binária no arranjo de N elementos. Qual é a complexidade da busca de X em notação BigOh nopior caso?

25. Para o código a seguir, indique o trecho crítico do programa (isto é, as linhas que se repetem mais vezes).Determine o valor da variável sum ao final. Indique a complexidade no pior caso em notação BigOh.Justifique.

1 sum = 02 f o r i in range ( n ) :3 f o r j in range ( n∗ i ) :4 f o r k in range ( 0 , j ) :5 sum += 1

DICA: O resultado é O(N5), pois o valor de sum atinge N5/6−N4/4−N3/6 +N2/4.

26. Para o código a seguir, indique o trecho crítico do programa. Determine o valor da variável sum ao final.Indique a complexidade no pior caso em notação BigOh. Justifique.

1 sum = 02 f o r i in range ( n ) :3 sum += 14 f o r i in range ( n ) :5 f o r j in range ( i ∗ i ) :6 i f ( j%i ) == 0 :7 f o r k in range ( j ) :8 sum += 1

DICA: O resultado éO(N4), pois o valor de sum atinge N4/8− 5N3/12+3N2/8− 11N/12. Este valor

é obtido pela expressãoN−1∑i=0

1 +

N−1∑i=1

i−1∑j=0

ij−1∑k=0

1.

Note o efeito da operação % na complexidade do programa.

Page 6

Page 7: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

27. Considere as seguintes funções:

1 def cube ( n ) :2 aux = 03 f o r i in range ( 1 , n + 1 ) :4 aux += i ∗ i ∗ i5 re turn aux67 def s q u a r e ( n ) :8 aux = 09 f o r i in range ( 1 , n + 1 ) :

10 aux += i11 re turn aux ∗ aux12 }

(a) Indique a complexidade dos dois métodos em notação BigOh.

(b) Demonstre que os dois métodos retornam o mesmo valor.

(c) Escreva um método que retorna o mesmo valor em tempo O (1).

28. Considere o seguinte teorema (conhecido como Teorema do Limite Superior): um politopo com N vérticesem D dimensões tem KND/2 faces para uma constante K > 0 e para qualquer N maior que um certo M .A partir desse teorema, prove que a ordenação e impressão das faces de um politopo com N vértices em 4dimensões pode ser feita em O

(N2 logN

). Justifique a partir da definição da notação BigOh.

DICA: Lembre-se que um politopo é um objeto geométrico definido por hiperplanos em um espaço com Ddimensões (para D = 2, temos poliedros).

29. Considere um programa com dois métodos. O primeiro método recebe um número N e produz um arranjoa de tamanho N !, onde cada elemento do arranjo é uma permutação do arranjo b igual a [1, 2, ..., N ](existem N ! permutações de uma lista com N elementos). Suponha que a seja ordenado de alguma forma,e o segundo método realiza uma busca binária em a. Prove que a complexidade do segundo método éO (N logN), usando a aproximação de Stirling:

N ! =√2Nπ(N/e)N (1 +O (1/N)).

30. Considere o seguinte método:

def d o I t ( a , b ) :o rd en a ( a )f o r i in range ( b ) :

aux = b u s c a _ b i n a r i a ( a , b [ i ] )f o r j in range ( aux , l e n ( a ) ) :

p r i n t t ( a [ j ] )

onde:

• void ordena(a) é uma função que faz o ordenamento do arranjo a).

• search(a, x) é uma função que faz busca binária do elemento x no arranjo a e retorna o índicede x em a.

• a e b são arranjos de tamanho máximo N .

• todos os elementos de b estão em a (os elementos de b podem ser repetidos).

Qual a complexidade em notação BigOh no pior caso em função de N para (justifique!):

(a) método ordena implementado com ordenação por inserção.

(b) método ordena implementado com mergesort.

31. Você foi chamado por uma empresa para analisar um bloco fundamental de programas de controle de fluxode caixa. Você identificou que o seguinte método é chamado muito frequentemente:

Page 7

Page 8: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

def d o i t ( a ) :sum = 0aux = 1f o r i in range ( l e n ( a ) ) :

sum += 1aux ∗= a [ i ]

f o r i in range ( l e n ( a ) ) :f o r j in range ( a ) :

sum += 1aux += ( a [ i ] − a [ j ] )

f o r i in range ( l e n ( a ) ) :f o r j in range ( i , 2∗ i ) :

f o r k in range ( j , j + 5 ) :sum++;

re turn sum + aux

(a) Determine a complexidade do programa em função deN , o tamanho do vetor de entrada a, em notaçãoBigOh. Justifique.

(b) Codifique o programa de forma que o resultado seja o mesmo mas a complexidade seja O (N). Justi-fique.

32. (*) (P1 2015) O fator h é uma métrica que mede a produção de um pesquisador, que combina quantidadede publicações com frequência na qual estas são citadas. Define-se fator h de um pesquisador como onúmero máximo n de publicações que ele produziu que foram citadas ao menos n vezes cada uma. Porexemplo, um pesquisador que possui 5 publicações que foram citadas respectivamente {5, 4, 3, 2, 1} vezespossui um fator h de 3, visto que as 3 publicações mais citadas foram citadas ao menos 3 vezes cada enenhuma das subsequentes foi citada 4 vezes. Já um pesquisador com 10 publicações que foram citadas{11, 10, 6, 5, 4, 3, 2, 1, 1, 1} vezes possui um fator h de 4 (verifique!).

a) Escreva uma função em Java que, dado um vetor com a quantidade de citações que cada uma das pu-blicações de um pesquisador recebeu ordenado em ordem decrescente, calcula o fator h. A função devepossuir a seguinte assinatura:

def fatorh(citacoes):

Nota: há uma solução trivial com complexidade O(N) mas o aluno deve ser capaz de encontrar umacom complexidade O(logN).

b) Explique como, dado o seu conhecimento de algoritmos, é possível calcular o fator h a partir de umalista desordenada com complexidade O(N logN).

33. Uma função recursiva sub2(a,k) recebe como entrada uma sequência a de tamanho N e um inteiro kque indica o nível da recursão. A função é sempre chamada como sub2(a,0). Uma análise da funçãoindicou que seu custo T (N) é O(1) para N = 1 e (α > 0 é uma constante)

T (N, k) =

{2T (N/2, k + 1) + αN, para k par,4T (N/2, k + 1) + αN, para k ímpar.

Obtenha o custo da chamada SUB2(a,0) assumindo que N é uma potência de 2.

34. (*) (P1 2015) A listagem a seguir mostra uma implementação do algoritmo de transformada rápida deFourier segundo o algoritmo de Cooley-Tuckey:

1 import math2 import cmath34 def f f t ( x ) :5 # Funcao r e c u r s i v a6 def f f t _ r e c ( x , y , s t a r t , n , s ) :7 i f n ==1: re turn8

Page 8

Page 9: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

9 f f t _ r e c ( y , x , s t a r t , n / / 2 , s ∗2)10 f f t _ r e c ( y , x , s t a r t +s , n / / 2 , s ∗2)1112 f o r k in range ( n / / 2 ) :13 a r g = −2∗math . p i ∗ ( k / n )14 t = y [ s t a r t +s ∗ (2∗ k +1) ]∗ cmath . r e c t ( 1 , a r g )15 x [ s t a r t +k∗ s ] = y [ s t a r t +k∗2∗ s ] + t16 x [ s t a r t +( n / / 2 + k )∗ s ] = y [ s t a r t +k∗2∗ s ]− t1718 # aux r e c e b e uma c o p i a de x19 # ATENCAO: Es ta operacao tem c o m p l e x i d a d e O( l e n ( x ) ) !20 aux = l i s t ( x )21 # Chama a f un ca o r e c u r s i v a22 f f t _ r e c ( x , aux , 0 , l e n ( x ) , 1 )

Este algoritmo trabalha exclusivamente com vetores cujo tamanho é uma potência de 2. O seu ponto deentrada é a função fft, que por sua vez chama a função recursiva fft_rec.

a) Mostre que o algoritmo sempre termina para um vetor com tamanho igual a uma potência de 2.

b) Escreva a equação de recorrência que dá a ordem, em notação big Oh, do tempo de execução destealgoritmo para uma entrada de tamanho N . Considere que todas as operações com números complexostêm complexidade constante O(1).

c) Resolva a equação e obtenha a ordem em notação big Oh do tempo de execução do algoritmo.

35. Considere uma recursão em que cada problema de tamanhoN é dividido recursivamente em 4 sub-problemas.Cada um desses sub-problemas tem tamanho N/2. Assuma que N é um número cujo logaritmo em umabase conveniente é um número inteiro. Qual é a complexidade dessa recursão para um problema de tama-nho N , se o “custo” de unir as soluções dos quatro sub-problemas de um único problema de tamanho N éexatamente N2, e o “custo” de resolver um problema com N = 1 é exatamente 1.

DICA: Considere o primeiro caso. A recursão leva à seguinte expressão:

T (N) = 4T (N/2) +N2.

Podemos escreverT (N/2) = 4T (N/4) +N2/4

e portanto:T (N) = 16T (N/4) +N2 +N2.

Da mesma forma:

T (N/4) = 4T (N/8) +N2/16⇒ T (N) = 64T (N/8) +N2 +N2 +N2.

Seguindo nesse raciocínio, atingimos:

T (N) = 4kT (N/2k) + kN2.

Para k = log2N (pois a árvore de recursão terá tamanho log2N ):

T (N) = N2T (1) +N2 log2N.

Portanto a complexidade é O(N2 logN

).

Tente resolver para o caso em que o “custo” de unir soluções é N3; a solução é O(N3). Lembre-se da

expressão:n∑k=0

ak = (a(n+1) − 1)/(a− 1).

36. (*) (PSUB 2015) Considere o problema de se determinar se um núumero está ou não presente em umamatriz na qual todas as colunas e linhas estão ordenadas em ordem crescente. Exemplo: 1 3 10 23

4 7 18 367 12 26 44

Page 9

Page 10: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

Uma maneira de se resolver este problema é dividir a matriz em quatro quadrantes, noroeste, nordeste,sudeste e sudoeste. Em seguida, o valor na posição no centro da matriz é verificada. Caso ele seja maiordo que o núumero procurado, o quadrante “sudeste” (inferior direito) é removido da busca (acrescido dacoluna e linha centrais) e a busca prossegue nos 3 quadrantes seguintes. Caso ele seja menor, o quadrante“noroeste” (acrescido da coluna e linha centrais) é eliminado da busca e ela prossegue nos 3 quadrantesrestantes. A listagem a seguir contém uma implementação em Java deste algoritmo:

def p r o c u r a ( v , a ) :def p r o c u r a _ r e c ( o , e , n , s ) :

i f o > e or n > s : re turn F a l s ex = ( o + e ) / / 2 # Coordenadas doy = ( n + s ) / / 2 # c e n t r ot = a [ y ] [ x ]i f v == t : re turn True # Achoue l i f v > t : # D e s c a r t a c a n t o NO

re turn p r o c u r a _ r e c ( x + 1 , e , n , y ) or \p r o c u r a _ r e c ( x + 1 , e , y + 1 , s ) or \p r o c u r a _ r e c ( o , x , y + 1 , s )

e l s e : # D e s c a r t a c a n t o SEre turn p r o c u r a _ r e c ( x , e , n , y − 1) or \p r o c u r a _ r e c ( o , x − 1 , y , s ) or \p r o c u r a _ r e c ( o , x − 1 , n , y − 1)

re turn p r o c u r a _ r e c (0 , l e n ( a [0] ) −1 , 0 , l e n ( a )−1)

A matriz é representada por um vetor de linhas, passado no parâmetro a. O parâmetro v contém o valor aser procurado. A função procura(v, a) chama a função recursiva procura_rec(o, e, n, s),na qual os parâmetros o, e, n e s são os limites da matriz a oeste (esquerda), leste (direita), norte (acima) esul (abaixo).

a) Escreva a equação de recorrência da ordem de complexidade deste algoritmo em função deN , o númerototal de elementos da matriz.

b) Resolva a equação de recorrência do item anterior e compare este algoritmo com uma busca sequencialna matriz.

37. Resolva a seguinte equação, resultado da análise de um algoritmo recursivo:

T (N) = aT (N/b) +N logN,

para:

(a) a igual a 3 e b igual a 2.

(b) a igual a 2 e b igual a 2.

(c) a igual a 2 e b igual a 3.

Assuma que N é uma potência na base mais conveniente e que T (1) = 1.

38. Considere o seguinte programa recursivo:

def d o i t ( a , i , j ) :n = j − i − 1i f n <= 1 :

re turn 1e l s e :

re turn d o I t ( a , i , i +n / / 2 −1 ) + \d o I t ( a , i +n / / 4 , i +3∗n / /4−1) + d o i t ( a , i +n / / 2 , j )

Considere agora o seguinte método:

def do ( a ) :re turn d o i t ( a , 0 , l e n ( a ) − 1)

Qual é a ordem de complexidade da chamada do(a) para um vetor a de tamanho N , em notação BigOh?Assuma que N é uma potência de 2.

Page 10

Page 11: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

39. Considere o seguinte fragmento de código, onde a e b são arranjos de mesmo tamanho N (onde N > 2) ea funçãoinsertionsort(a, o, f)ordena o arranjo a entre o e f, usando ordenação por inserção.

p u b l i c vo id d o i t ( a , b , o , f ) :i f ( f−o ) < 2 :

re turn a [ f ]e l s e :

i n s e r t i o n s o r t ( a , o , f )i f a [ 0 ] < b [ 0 ] :

d o t i t ( a , b , o , ( f +o ) / / 2 )e l s e :

l s t l i s t i n g ( a , b , ( f +o ) / / 2 , f )i f ( a [ 1 ] < b [ 1 ] )

d o i t ( a , b , o + ( f−o ) / / 4 , o + 3∗ ( f−o ) / / 4 ) ;d o i t ( a , b , o , o + ( f−o ) / / 3 ) ;

}

Escreva a equação recursiva que deve ser resolvida para obter a complexidade deste fragmento de códigoem notação BigOh, considerando o pior caso. Indique também as condições de contorno que devem seratendidas pela solução (isto é, qual a complexidade da parada da recursão). Justifique a resposta. [Note:não há necessidade de resolver a equação!]

40. (*) (P1 2015) O código a seguir mostra uma implementação em java do algoritmo de ordenação Quicksortpara vetores de inteiros entre os índices a e b:

1 def q u i c k s o r t ( s , a , b ) :2 i f a >=b :3 re turn4 p = s [ b ] # p i v o t5 l = a6 r = b−17 whi le l <= r :8 whi le l <= r and s [ l ] <=p :9 l = l +1

10 whi le l <= r and s [ r ] >=p :11 r = r − 112 i f l < r :13 temp = s [ l ]14 s [ l ] = s [ r ]15 s [ r ]= temp16 s [ b ] = s [ l ]17 s [ l ] = p18 q u i c k s o r t ( s , a , ( l −1))19 q u i c k s o r t ( s , ( l +1 ) , b )

Esta implemenação escolhe como pivô o último elemento do vetor. O vetor é dividido em dois sub-vetores,um de a a l − 1 e outro de l + 1 a b de modo que no primeiro há somente elementos menores ou iguais aopivô e no segundo somente elementos maiores ou iguais ao pivô.

a) Em sua tese de doutorado em 1975, Robert Sedgewick propôs uma alteração no algoritmo: A primeirachamada recursiva do algoritmo deve ser feita sobre o menor dos sub-vetores. Reescreva o algoritmoacima de modo a comparar o tamanho relativo dos subvetores após a divisão e fazer as chamadas recur-sivas de acordo com o proposto por Sedgewick.

b) Reescreva o algoritmo do item (b) de modo a transformar a chamada de cauda (ou seja, a última chamadada função) em um laço.

c) O objetivo da modificação de Sedgewick é reduzir a profundidade máxima da árvore de chamadas econsequentemente o uso de memória de pilha pelo algoritmo. Qual a ordem em notação big Oh da

Page 11

Page 12: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

profundidade máxima da árvore de chamadas do algoritmo produzido no item (c) para um vetor de Nposições?

41. Resolva as seguintes equações recursivas, expressando o resultado em notação BigOh e assumindo que Né uma potência na base mais conveniente:

• T (1) = 1, T (N) = 3T (N/2) +N .

• T (1) = 1, T (N) = 7T (N/3) +N2.

• T (1) = 1, T (N) = 2T (N − 1) +N .

Respostas para Exercícios selecionadosExercício 2

def p r o d u t o ( a , b ) : # a e b tem o mesmo tamanhoprod = 0f o r i in range ( l e n ( a ) ) :

t o t a l += a [ i ]∗ b [ i ]re turn t o t a l

As pré-condições são:• a = {a0, . . . , an} , b = {b0, . . . , bn} , n ∈ N.

a e b são vetores de tamanho finito (potencialmente nulo) e idêntico.

• Os componentes ai e bi são todos números de ponto flutuante.

A pós-condição (desejada) é:

produto (a, b) =

n∑k=0

akbk

Seja ij e pj respectivamente os valores das variáveis i e prod ao final da j-ésima iteração do laço. As regrasde transição são:

ij+1 =ij + 1

pj+1 =pj + aibi

com valores iniciais i0 = 0 e p0 = 0.A condição de permanência no laço é i ≤ n. Claramente, o valor de i ao final da iteração é idêntico ao número

da iteração. Assim, são realizadas exatas n iterações e o algoritmo termina em tempo finito.Para demostrar a correção, basta mostrar que a identidade

pj =

j−1∑k=0

akbk

permanece válida em todas as iterações.Ora, ela é trivialmente verdadeira para j = 0, quando p0 = 0. Por indução finita,

pj+1 = pj + aibi =

j−1∑k=0

akbk + ai + bi =

j∑k=0

akbk

Assim, se a afirmação é válida para j, também o é para j + 1.Na condição de parada, ij = n+ 1 =⇒ j = n+ 1 e o valor retornado é produto (a, b) = pn+1. Ora, mas

pelo invariante, pn+1 =∑nk=0 akbk, a pós-condição desejada.

Page 12

Page 13: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

Exercicio 3a) Implementação em Python:

def gcd(a, b):while a!=b:

r = a - bwhile (r%2)==0:

r//= 2if r>b:

a = relse: # Garante que a > b

a = bb = r

return a

b) Considere-se o código do item anterior, e sejam ti, ai, bi os valores das variáveis temp, a e b ao final dai-gésima iteração. Seja 2ki a maior potência de 2 que divide exatamente (ai− bi). As leis de recorrência destealgoritmo podem ser escritas como:

ti+1 =ai − bi2ki

(1)

ai+1 = max(ti+1, bi) (2)bi+i = min(ti+1, bi) (3)

Por (1), ti é sempre ímpar, e consequentemente, também o são ai e bi. Ademais, ti+1 ≤ (ai − bi) < ai ⇒ti+1 < ai. Por outro lado, ti+1 > 0. Das regras de recorrência em (2) e (3), ai > ai+1 ≥ bi+1 > 0. Comoa sequencia de inteiros ai é estritamente decrescente e a bi é limitada inferiormente por 0 e superiormente porai, então a condição de saída bi = ai é inevitável.

c) Nota-se que independentemente do resultado do teste na linha 6, tem-se (por comutatividade do máximo divisorcomum) gcd(ai+1, bi+1) = gcd(ti+1, bi). Ora, mas por (1) gcd(ti+1, bi) = gcd

((ai − bi) /2ki , bi

). Observa-

se que por (1) a sequência de valores ti é sempre ímpar. Assim, também o é a sequência bi. Deste modo,gcd

((ai − bi) /2ki , bi

)= gcd ((ai − bi) , bi). Finalmente, gcd ((ai − bi) , bi) = gcd (ai, bi), ou seja:

gcd (ai+1, bi+1) = gcd (ai, bi) (4)

Isso significa que o valor gcd (ai, bi) é invariante no algoritmo! Seja n a iteração na qual an = bn. Entãogcd (a0, b0) = gcd (an, bn) = an.

d) Nota-se que o maior dos valores (ou seja, o da varíavel a) é sempre substituído ao final da iteração, seja pelavariável b ou pela variável temp, ambas valores ímpares. Deste modo, quando o maior dos valores é par, apósa primeira iteração, o algoritmo passa a trabalhar com dois valores ímpares.

O cenário em que b0 é par é mais complexo. Enquanto ai − bi > bi, vale a recorrência ai+1 = ai − bi ebi+1 = bi, de modo que bi mantém-se par. Ora, mas isso vale apenas para i ≤ ba0/b0c. Na última iteração,ai+ 1 = bi e bi+1 = ai − bi. Neste momento, o número par passa ser o armazenado na variável a e, comovisto no caso anterior, o algoritmo termina.

Nota: Embora estritamente falando neste último caso o algoritmo ainda funcione, ele potencialmente trabalhacom um desempenho extremamente deteriorado. De fato, são necessárias ba0/b0c + 1 iterações até que oalgoritmo possa voltar a trabalhar com dois números ímpares, o que potencialmente pode ser um númeromuito grande.

e) É fácil encontrar um exemplo para o qual o algoritmo falha quando os dois números são pares. Considere-se ocálculo de gcd(4, 2) = 2. Eis a sequência de funcionamento do algoritmo.

Pode-se ver que a resposta final do algoritmo é 1, e não a correta, 2. Isso acontece pela divisão de ai − bi por2 na primeira iteração. Como bi é par, não vale gcd

((ai − bi) /2ki , bi

)= gcd (ai − bi, bi).

A prova de correção do algoritmo usa a propriedade de que se a e b são pares, então gcd (a, b) = 2gcd (a/2, b/2):

Page 13

Page 14: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

i ti ai bi

0 - 4 21 1 2 12 1 1 1

Tabela 1: Algoritmo de Euclides Binário com duas entradas pares

def gcd ( a , b ) :f a t o r = 1 ;whi le ( a%2)==0 and ( b %2)==0:

a / / = 2 ;b / / = 2 ;f a t o r ∗=2;

whi le ( a %2)==0:a / / = 2 ;

whi le ( b %2)==0:b / / = 2 ;

i f b>a : # Garante a > ba , b = b , a

whi le a != b :r = a − bwhi le ( r %2)==0:

r / / = 2i f r >b :

a = re l s e : # Garante que a > b

a = bb = r

re turn f a t o r ∗a

Exercício 5Do sabido sobre o algoritmo de Euclides, mostra-se que o algoritmo termina em tempo finito e que o valor finalobtido, an (sendo n a última iteração do laco iniciado na linha 4) é efetivamente o valor de gcd(a0, b0). Restaprovar que an = xana0 + yanb0.

Sabe-se pelas linhas de 8 a 18 do algoritmo que

ai+1 = bi (5)

qi+1 =

⌊aibi

⌋(6)

bi+1 = ai − qi+1bi (7)xbi+1 = xai − qi+1xbi (8)ybi+1 = yai − qi+1ybi (9)xai+1 = xbi (10)yai+1 = ybi (11)

Page 14

Page 15: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

A relação

ai = xaia0 + yaib0

bi = xbia0 + ybib0

é trivialmente verdadeira para i = 0, visto que xa0 = yb0 = 1 e ya0 = xb0 = 0.Ora, mas por indução finita, supondo que a relação é válida para i, segue-se que:

xbi+1a0 + ybi+1b0 = (xai − qi+1xbi) a0 + (yai − qi+1ybi) b0

=

ai︷ ︸︸ ︷xaia0 + yaib0−qi+1

bi︷ ︸︸ ︷(xbia0 + ybib0)

= ai − qi+1bi

= bi+1

e

xai+1a0 + yai+1b0 = xbia0 + ybib0 = bi = ai+1

Logo a relação é verdadeira em todas as iterações do algoritmo.

Exercício 6a) Seja i o número de iterações realizadas pelo laço da linha 3, ai, ri e xi o valor das variáveis a, r e x respecti-

vamente após a execução da linha 8 na i-gésima iteração. Assim, pelas linhas 6 e 7, ai+1 < ai. No entanto,ai ≥ 0, pois a variável a só é submetida a operações de divisão por 2 e decremento quando é par não-nulo.Conclui-se daí que ai é estritamente decrescente mas limitado inferiormente por 0. Como ai é uma sequênciainteira, há um número finito possível de iterações.

b) Há dois caminhos que o algoritmo pode seguir, dependendo da paridade da variável ai:

ai é par:

Neste caso:

ai+1 =⌊ai2

⌋=ai2

ri+1 = ri

xi+1 = xi2

Neste caso,

ri+1xi+1ai+1 = ri

(xi

2) ai

2

= rixiai

ai é ímpar:

Neste caso:

ai+1 =

⌊ai − 1

2

⌋=ai − 1

2

ri+1 = rixi

xi+1 = xi2

Neste caso,

ri+1xi+1ai+1 = rixi

(xi

2) ai−1

2

= rixixiai−1 = rixi

ai

Seja como for, vale ri+1xi+1ai+1 = rixi

ai , ou seja, o valor rixiai é invariante no algoritmo. Ora, mas parai = 0, vale rixiai = x0

a0 , ou seja, o valor xa procurado. Por outro lado, se n é a iteração final na qual an = 0,então rnxnan = rn, que é o valor retornado pelo algoritmo. Deste modo, conclui-se que rn = x0

a0 , ou seja,o algoritmo efetivamente retorna o valor xa.

Exercício 7a) Seja xi o valor da variável x ao final da execução da linha 8, na i-gésima iteração do laço iniciado na linha 3.

Pela linha 8, xi+1 = bxi/10c e assim xi+1 < xi. Por outro lado, xi ≥ 0⇒ xi+1 ≥ 0. Assim, a sequência xié inteira, estritamente decrescente e limitada inferiormente por 0. Existe portanto um valor finito n para o qualxn = 0, condição de encerramento do laço.

Page 15

Page 16: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

b) Seja ri o inteiro representado pelo i-gésimo dígito da cadeia em r, da direita para a esquerda e com o índice doprimeiro dígito igual a 1 (atenção!). Pela linha 7, a i-gésima iteração adiciona à cadeia exatamente o i-gésimodígito, mantendo os anteriores inalterados. Seja Ri o valor representado pela cadeia em r. Seja n o índice dodígito final da cadeia em r, que é também o número da iteração do algoritmo, quando vale xn = 0.

Diz-se que a representação final em r está correta se e somente se

0 <= ri <= 9 (12)

e

Rn =

n∑i=1

ri · 10i−1 = x0 (13)

Pelo algoritmo,

ri+1 = xi mod 10 (14)

xi+1 =⌊xi10

⌋(15)

A condição (12) é trivialmente satisfeita por (14). Sabe-se que

Ri+1 = Ri + ri+1 · 10i (16)

Por outro lado, ⌊xi10

⌋=xi − (xi mod 10)

10=xi − ri+1

10

Assim,xi+1 · 10i+1 =

xi − ri+1

1010i+1 = xi · 10i − ri+1 · 10i (17)

Somando-se (16) e (17), chega-se a:

Ri+1 + xi+1 · 10i+1 = Ri + xi · 10i

Ou seja, o valor Ri + xi · 10i é invariante no algoritmo. No início do algoritmo, R0 = 0. No final, xn = 0.Assim, Rn = x0, o que comprova o funcionamento do algoritmo.

Exercicio 8a) Note que embora a matriz a esteja pré-alocada, seu conteúdo é indeterminado.

def m a t r i x m u l t ( x , y , a ) :f o r i in range ( l e n ( a ) ) :

f o r j in range ( l e n ( a [ i ] ) ) :t o t a l = 0f o r k in range ( l e n ( y ) ) :

t o t a l += x [ i ] [ k ] ∗ y [ k ] [ j ]a [ i ] [ j ] = t o t a l

b) Há 3 laços, cada um com N iterações. Assim a complexidade é O(N3).

Exercício 15Seja o conjunto A representado pelo vetor a = {a0, a1, . . . , an}. Temos 3 possibilidades:

1. Existe um subconjunto cuja soma é exatamente k que contém an.

2. Existe um subconjunto cuja soma é exatamente k que não contém an.

Page 16

Page 17: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

3. Não existe subconjunto cuja soma é exatamente a

Ao menos uma destas 3 opções deve ser verdadeira. Assim, testando-se os casos 1 e 2 é possível determinarse o subconjunto existe ou não. De fato, se existe um subcojunto de A que contém an cuja soma é exatamente k,então existe um subconjunto deA\{an} = {a0, a1, . . . , an−1} cuja soma é exatamente k−an. Por outro lado, sehá um subconjunto de A que não contém an cuja soma é exatamente k, então evidentemente há um subconjuntode {a0, a1, . . . , an−1} cuja soma é exatamente k. Deste modo, é possível resolver o problema para um vetor detamanho n resolvendo dois problemas com vetores de tamanho n− 1, testando as duas possibilidades.

O caso base é o do vetor nulo, para o qual a resposta só é verdadeira se k = 0.

def Exis teSubSoma ( a , k ) :def ExisteSubSomaRec ( u l t imo , k ) :

i f u l t i m o < 0 : re turn k==0re turn ExisteSubSomaRec ( u l t imo −1, k−a [ u l t i m o ] ) or ExisteSubSomaRec ( u l t imo −1,k )

re turn ExisteSubSomaRec ( l e n ( a )−1 , k )

A lei de recorrência que rege a complexidade deste algoritmo é:

T (N) = 2T (N − 1) +O (1)

Cuja solução é T (N) = O(2N).

Nota: é possível obter também os componentes da sequência desejada:

def Encont raSubSeq ( a , k ) :def Encont raSubSeqRec ( u l t imo , k ) :

i f u l t i m o < 0 :i f k ==0: re turn True , [ ]e l s e : re turn F a l s e , None

E x i s t e , seq = Encont raSubSeqRec ( u l t imo −1, k−a [ u l t i m o ] )i f E x i s t e : re turn True , seq + [ a [ u l t i m o ] ]E x i s t e , seq = Encont raSubSeqRec ( u l t imo −1, k )i f E x i s t e : re turn True , seqre turn F a l s e , None

re turn Encont raSubSeqRec ( l e n ( a )−1 , k )

Exercício 17a) Seja ui o valor da variável ultimo ao final da execução da linha 11, na i-gésima iteração do laço externo

(iniciado na linha 3). O laço na linha 5 vai executar um total de ui passos. Seja ai o valor da variávelultimo_alterado ao final da execução da linha 10, na i-gésima iteração do laço interno. O valor máximode ai é (ui − 1), quando o último elemento a ser inspecionado pelo laço interno é modificado (isso ocorrepor exemplo com uma entrada em ordem inversa, na qual o laço interno transporta o primeiro elemento até aposição ui e mantém a ordem relativa dos demais elementos inalterada). Assim, o valor máximo que ui podeassumir é (ui−1 − 1). Ou, seja, no pior caso, ui segue uma sequência aritmética decrescente de razão -1. Onúmero total de iterações do laço interno no pior caso para uma entrada com n elementos é dado por:

1∑i=n−1

i =n2 − n

2= O

(n2)

b) Do mesmo modo, o valor mínimo que ai pode assumir na primeira iteração é 0, quando nenhuma posição émodificada (como por exemplo com uma entrada ordenada). Neste caso a complexidade é O (n).

Exercício 20Trata-se de um algoritmo recursivo. Sejam i, j os valores das variáveis i, j em uma dada chamada da função(como o algoritmo é recursivo, estes valores são específicos de um dado escopo). Seja k = bj − ic /3. Seja

Page 17

Page 18: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

A = {di, . . . , dj} o valor da variável mathtta antes da chamada a ordena(a, i, j) e A∗ o valor da mesmavariável após a chamada.

As pós-condições desejáveis são:

1. a∗l+1 ≥ a∗l ∀ i ≤ l < j, ou seja, o vetor A∗ está em ordem crescente.

2. ∃π : N[i,j] �� N[i,j] | al = a∗π(l), ou seja, existe uma permutação (representada como a função bijetora π)de A em A∗.

3. a∗l = al ∀ i < l ∨ l > j, ou seja, os eventuais elementos de A fora do intervalo de índices i, j permaneceminalterados.

Trata-se de um algoritmo recursivo cujo caso-base é i− j ≤ 2, ou seja o vetor a ser ordenado tem no máximoduas posições. O algoritmo chama a si próprio 3 vezes, com índices (i, j − k), (i+ k, j) e (i, j − k) novamente.

Ora, mas é fácil mostrar que fora do caso-base, k = bj − i+ 1c /3 ≥ 1. Isso significa que diferença i − jem cada nível de chamada da função é um valor inteiro, estritamente decrescente e limitado inferiormente. Destemodo o caso-base é sempre atingido.

No caso-base, o algoritmo troca as eventuais duas posições do vetor caso elas estejam fora de ordem (ou nãofaz nada se o vetor é unitário). Deste modo, as duas pós-condições são trivialmente satisfeitas.

Ora, mas se as 3 sub-chamadas efetivamente ordenam os respectivos sub-vetores, então, seja A1 o conteúdodo vetor a após a 1a chamada. Neste caso vale:

a1l+1 ≥ a1l ∀ i ≤ l ≤ (j − k)∃ ρ1 : N[i,j−k] �� N[i,j−k] | al = aρ1(l)

a1l = al ∀ (j − k) < l ≤ j

Ou seja, o intervalo entre índices i, j−k da sequênciaA1 (denotadoA1i:j−k) está ordenado em ordem crescente

do no intervalo de e os valores neste intervalo são obtidos de uma permutação dos valores de A no mesmointervalo. Os demais valores permanecem inalterados, ou seja, A1

j−k+1:j = Aj−k+1:j (logo há uma permutaçãoπ1 : N[i,j] �� N[i,j] tal que al = aπ1(l)).

A propriedade de ordenação em particular garante que:

a1m ≤ a1n ∀ i ≤ m < (i+ k) ≤ n ≤ (j − k)

Isso significa que se há a1o < am com i ≤ m < (i+ k) e (k+1) ≤ o ≤ j então necessariamente o > (j− k).Assim, há no máximo k elementos na subsequência A1

i+k:j que podem ser menores do que algum elemento deA1i:i+k−1.

Se A2 é o valor do vetor a depois da segunda chamada, então:

a2l+1 ≥ a2l ∀ (i+ k) ≤ l ≤ j∃ ρ2 : N[i+k,j] �� N[i+k,j] | a2l = a1ρ2(l)

a2l = a11 ∀ i ≤ l < i+ k

Do mesmo modo, a propriedade de ordenação garante que:

a2m ≤ a2n ∀ (i+ k) ≤ m ≤ (j − k) < n ≤ j

Mostra-se, por absurdo, que além disso, todos os elementos deA2j−k+1:j são maiores do que qualquer elemento

de A2i,i+k−1. De fato, sabe-se devido à existência de ρ2 e às propriedades da primeira chamada que há no máximo

k elementos em A2i+k,j que podem ser menores do que algum elemento de A2

i:i+k−1. Por outro lado, se ouvessealgum elemento em A2

j−k+1:j menor do que algum elemento de A2i:i+k−1, então a propriedade de ordenação

exigiria que ouvessem ao menos j − i− 2k também menores. Ora, mas:

j − i− 2k = j − i− 2

⌊j − i3

⌋> j − i− 2

j − i3

=j − i3

>

⌊j − i3

⌋= k

Isso é uma contradição de modo que não pode existir tal elemento. Assim, combinando esta propriedade coma de ordenação mostra-se que todos os elementos emA2

j−k+1:j são maiores do que todos os elementos emA2i:j−k.

Page 18

Page 19: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

A terceira chamada completa a ordenação, pois após esta,

a3l+1 ≥ a3l ∀ (i) ≤ l ≤ (j − k)∃ ρ3 : N[i,j−k] �� N[i,j−k] | a3l = a2ρ3(l)

a3l = a21 ∀ (j − k) < l ≤ j

Deste modo, os elementos em A3i:j−k estão ordenados. Ora, mas também o estão os elementos de A3

j−k+1,j

(que não foram modificados). Além disso, todos os elementos emA3i:j−k são menores ou iguais aos elementos em

A3j−k+1,j . Assim, o vetor A3 está completamente ordenado. É trivial mostrar que ele é uma permutação do vetor

original. Como A3 = A∗, as pós-condições originais são atendidas.Quanto à complexidade, ele faz operações em tempo constante e em seguida chama a si próprio 3 vezes com

entradas com 2/3 do tamanho original.Na notação do Teorema-Mestre,

T (N) = 3T

(N

3/2

)+O

(N0)

Deste modo,

T (N) = O(N log3/2 2

)≈ O

(N1,71

)Exercício 32a) Uma solução trivial com complexidade O(N):

def f a t o r h ( c i t a c o e s ) :i =0whi le i < l e n ( c i t a c o e s ) and c i t a c o e s [ i ] >=( i + 1 ) : i += 1re turn i

A versão com complexidade O(logN) usa as mesmas idéias básicas de uma busca binária:

def f a t o r h ( c i t a c o e s ) :a = 0b = l e n ( c i t a c o e s )b e s t = 0whi le a <=b :

r e f = ( a+b ) / / 2i f c i t a c o e s [ r e f ] >=( r e f + 1 ) : # Procura na metade s u p e r i o r

b e s t = r e fa = r e f + 1

e l s e : # Procura na metade i n f e r i o rb = r e f − 1

re turn b e s t +1

É possível ainda omitir completamente a variável best:

def f a t o r h ( c i t a c o e s ) :a = 0b = l e n ( c i t a c o e s )whi le ( a <=b ) :

r e f = ( a+b ) / / 2i f c i t a c o e s [ r e f ] >=( r e f + 1 ) : # Procura na metade s u p e r i o r

a = r e f +1e l s e : # Procura na metade i n f e r i o r

b = r e f − 1re turn a

Page 19

Page 20: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

Finalmente há uma versão recursiva bastante compacta:

def f a t o r h ( c i t a c o e s ) :def busca ( a , b ) :

i f a>b : re turn ar e f = ( a+b ) / / 2i f c i t a c o e s [ r e f ] >=( r e f + 1 ) : re turn busca ( r e f +1 , b )re turn busca ( a , r e f −1)

re turn busca ( 0 , l e n ( c i t a c o e s )−1)

b) O algoritmo de ordenação mergesort ordena um vetor com complexidadeO(N logN). Assim, a complexidadedas operações conjuntas ordenar por mergesort e calcular o fator h é de O(N logN +N) = O(N logN).

Exercício 34a) O algoritmo é um algoritmo recursivo cujo caso base é o parâmetro n igual a 1. Caso contrário, o algoritmo

chama a si mesmo duas vezes, passando n/2 como novo parâmetro n. Se o valor inicial de n, o tamanhoinicial do vetor, for exatamente uma potência de 2, as sucessivas divisões por 2 farão com que o caso base sejaatendido.

b) Seja T (N) a ordem de complexidade do algoritmo. O algoritmo chama a si mesmo duas vezes comN/2 comoparâmetro e realiza N · O(1) operações sobre os vetores. A equação é:

T (N) = 2T

(N

2

)+O(N)

c) Na notação do Master Theorem, temos A = 2, B = 2 e L = 1. Neste caso, tem-se exatamente A = BL dondea solução é:

T (N) = O(N logN)

Exercício 36a) Resposta: O algoritmo divide a matriz em 4 quadrantes, cada um com aproximadamente 1/4 do tamanho da

matriz original. Em seguida, chama a si mesmo em 3 destes quadrantes. A operação de divisão e escolha dequadrantes a rejeitar tem complexidade constante O(1). A equação recursiva é:

T (N) = 3T

(N

4

)+O(1)

b) Na notação do teorema Mestre, tem-se A = 3, B = 4 e L = 0. Neste caso, naturalmente, A > BL e a soluçãoé N logB A, ou seja,

T (N) = O(N log4 3

)≈ O

(N0,7925

)Exercício 37A equação a ser resolvida é

T (N) = aT

(N

b

)+N logN

Esta é uma equação recursiva, na qual o termo de uma ordem (T (N)) está expresso em função de N e dotermo de ordem imediatamente anterior (T (N/b)). Uma maneira de resolvê-la é escrever o termo de ordemimediatamente anterior (T (n/b)) em função de seu antecessor (T (N/b2)), usando para isso a própria equaçãorecursiva2:

2Esta é a maneira pela qual o Master Theorem é demonstrado no curso

Page 20

Page 21: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

T

(N

b

)= aT

(N

b2

)+N

blog

(N

b

)Substituindo-se na equação anterior,

T (N) = a2T

(N

b2

)+a

bN log

(N

b

)+N logN

Prosseguindo agora, escrevemos T (N/b2) em função de T (N/b3),

T

(N

b2

)= aT

(N

b3

)+N

b2log

(N

b2

)e

T (N) = a3T

(N

b3

)+a2

b2n log

(N

b2

)+a

bN log

(N

b

)+N logN

Repetindo-se este processo k passos, tem-se:

T (N) = akT

(N

bk

)+

k−1∑i=0

ai

biN log

(N

bi

)Se N = bk,

T (N) = ak

O(1)︷︸︸︷T (1)+

k−1∑i=0

(ab

)ibk log

(bk

bi

)

= akO(1) +k−1∑i=0

bk(ab

)i (log bk − log bi

)= akO(1) + bk log b

(k

k−1∑i=0

(ab

)i−k−1∑i=0

i(ab

)i)

= akO(1) + bk log(bk)(k−1∑

i=0

(ab

)i− 1

k

k−1∑i=0

i(ab

)i)

Existem formas fechadas para as duas séries do lado direito, que dependem da razão (a/b). Se a = b, entãoa/b = 1 e trivialmente,

T (N) = akO(1) + bk log(bk)k

Como N = bk e k = logbN ,

T (N) = O(N (logN)

2)

Para a!neqb usa-se resultados conhecidos de somas de séries. Com x 6= 1, vale3:

k−1∑i=0

xi =xk − 1

x− 1

k−1∑i=0

ixi =x

(x− 1)2 + xk

(k

x− 1− x

(x− 1)2

)Então, substituindo-se x = a/b e descartando-se os termos de menor ordem em k,

3Note que o segundo resultado é a derivada do primeiro multiplicada por x

Page 21

Page 22: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

k−1∑i=0

(ab

)i− 1

k

k−1∑i=0

i(ab

)i= O

((a/b)k+1

/k − 1

(a/b)− 1)

)Retomando-se N = bk e k = logbN ,

T (N) = N logb aO(1) +NO

((a/b)

logbN+1 − logbN

(a/b)− 1

)

Estamos então diante de 2 possibilidades:

1. a/b > 1. Neste caso, (a/b)logbN � logbN e

T (N) = O(N logb a

)2. a/b < 1. Neste caso, (a/b)logbN � logbN e

T (N) = O (N logN)

Resumindo, tem-se:

T (N) =

O (N logN) para a < b

O(N (logN)

2)

para a = b

O(N logb a

)para a > b

Em particular, para:

(a) a = 3, b = 3:T (N) = O

(N logb a

)≈ N1,585

(b) a = 2, b = 2:T (N) = O

(N (logN)

2)

(c) a = 2, b = 2:T (N) = O (N logN)

Exercício 40a) A quantidade de chamadas subsequente é limitada pelo tamanho do vetor de entrada. Assim, naturalmente,

a maior quantidade de chamadas ocorrerá quando um dos sub-vetores pós-divisão for o maior possível. Issoocorre por exemplo em um vetor pré-ordenado, quando o primeiro sub-vetor tem tamanho N − 1. Neste casoa profundidade máxima é O(N).

b) O resultado é idêntico à listagem do enunciado até a linha 17:

1 def q u i c k s o r t ( s , a , b ) :2 i f a >=b :3 re turn4 p = s [ b ] # p i v o t5 l = a6 r = b−17 whi le l <= r :8 whi le l <= r and s [ l ] <=p :9 l = l +1

10 whi le l <= r and s [ r ] >=p :11 r = r − 112 i f l < r :

Page 22

Page 23: Exercícios - Moodle USP: e-Disciplinas · 2017-04-08 · ... O algoritmo pode falhar quando ambos os números são pares ... inteiros A 1 a A N, e um inteiro Kmaior que todos os

13 temp = s [ l ]14 s [ l ] = s [ r ]15 s [ r ]= temp16 s [ b ] = s [ l ]17 s [ l ] = p18 i f ( l−1−a ) >( b−l −1):19 q u i c k s o r t ( s , a , ( l −1))20 q u i c k s o r t ( s , ( l +1 ) , b )21 e l s e :22 q u i c k s o r t ( s , ( l +1 ) , b )23 q u i c k s o r t ( s , a , ( l −1))

c) Note que é impossível retirar ambas as chamadas recursivas (ao menos sem uma estrutura de dados auxiliar(que por sua vez utilizaria uma quantidade de memória comparável à da pilha do programa).

def q u i c k s o r t ( s , a , b ) :whi le a < b :

p = s [ b ] # p i v o tl = ar = b−1whi le l <= r :

whi le l <= r and s [ l ] <=p :l = l +1

whi le l <= r and s [ r ] >=p :r = r − 1

i f l < r :temp = s [ l ]s [ l ] = s [ r ]s [ r ]= temp

s [ b ] = s [ l ]s [ l ] = pi f ( l−1−a ) >( b−l −1):

q u i c k s o r t ( s , a , ( l −1))a = l + 1

e l s e :q u i c k s o r t ( s , ( l +1 ) , b )b = l −1

d) A profundidade máxima ocorre quando o sub-vetor passado para a chamada recursiva tem o tamanho máximoa cada iteração. Ora, este sub-vetor tem no máximo o tamanho da metade do vetor original (visto que ele émenor ou igual ao outro sub-vetor). Finalmente, é possível dividir um vetor em 2 no máximo log2N vezes, demodo que a profundidade máxima é de ordem O(logN).

Page 23