Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter...

28
Programa¸c˜ ao Dinˆ amica Fernando Lobo Algoritmos e Estrutura de Dados 1 / 56 Programa¸c˜ ao Dinˆ amica Outra t´ ecnica de concep¸c˜ ao de algoritmos, tal como Divis˜ ao e Conquista. O termo Programa¸ ao Dinˆ amica ´ e um bocado infeliz. I Programa¸ ao sugere programa¸ ao de computadores. I Dinˆ amica sugere valores que mudam ao longo do tempo. A t´ ecnica de Programa¸c˜ ao Dinˆ amica n˜ ao tem que ver com uma coisa nem outra. 2 / 56

Transcript of Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter...

Page 1: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Programacao Dinamica

Fernando Lobo

Algoritmos e Estrutura de Dados

1 / 56

Programacao Dinamica

Outra tecnica de concepcao de algoritmos, tal como Divisao eConquista.

O termo Programacao Dinamica e um bocado infeliz.

I Programacao ⇒ sugere programacao de computadores.

I Dinamica ⇒ sugere valores que mudam ao longo do tempo.

A tecnica de Programacao Dinamica nao tem que ver com uma coisanem outra.

2 / 56

Page 2: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

O que e entao a Programacao Dinamica?

E uma tecnica de resolucao de problemas.

A ideia e resolver subproblemas pequenos e armazenar os resultados.

Esses resultados sao depois utilizados para resolver subproblemasmaiores (e armazenando novamente os resultados).

E assim sucessivamente ate se resolver o problema completo.

3 / 56

Comparacao com Divisao e Conquista

Semelhancas

Para resolver um problema combinamos as solucoes de subproblemas.

Diferencas

Divisao e Conquista e eficiente quando os subproblemas sao todosdistintos.

Se tivermos que resolver varias vezes o mesmo subproblema, aDivisao e Conquista torna-se ineficiente.

Com Programacao Dinamica cada subproblema e resolvido apenasuma vez.

4 / 56

Page 3: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Exemplos de Programacao Dinamica

A melhor maneira de aprender Programacao Dinamica e ver algunsexemplos.

Exemplo simples: Calcular o n-esimo numero da sequencia deFibonacci.

Fn =

0 , se n = 01 , se n = 1Fn−1 + Fn−2 , se n > 1

5 / 56

Pseudocodigo

Fib-Rec(n)

if n == 0return 0

if n == 1return 1

return Fib-Rec(n − 1) + Fib-Rec(n − 2)

Este algoritmo e muito mau. Porque?

6 / 56

Page 4: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Vejamos o que acontece com n = 5

7 / 56

Fibonacci: Algoritmo de Divisao e Conquista

Estamos a calcular a mesma coisa varias vezes!

Pode-se provar que Fn+1/Fn ≈ 1+√5

2 ≈ 1.62=⇒ Fn > 1.6n

Qual a complexidade do algoritmo?

I Fn resulta da soma das folhas da arvores.

I Fn > 1.6n =⇒ arvore tem pelo menos 1.6n folhas.

Logo, o algoritmo tem complexidade Ω(1.6n), o que e muito mau.

Experimentem programa-lo e usar n = 50.

8 / 56

Page 5: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Fibonacci: Algoritmo de Divisao e Conquista

No exemplo com n = 5, calculamos:

I F4 → 1 vez

I F3 → 2 vezes

I F2 → 3 vezes

I F1 → 5 vezes

I F0 → 3 vezes

E trabalho desnecessario. So deverıamos calcular cada Fi uma e umaso vez.

Podemos faze-lo usando Programacao Dinamica.

9 / 56

Fibonacci: Algoritmo de Programacao Dinamica

A ideia e resolver o problema de baixo para cima, comecando peloscasos base e armazenando as solucoes dos subproblemas.

Fib-PD(n)

F [0] = 0F [1] = 1for i = 2 to n

F [i ] = F [i − 1] + F [i − 2]return F [n]

Complexidade temporal? Θ(n).

Complexidade espacial? Θ(n).

10 / 56

Page 6: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Fibonacci: Algoritmo de Programacao Dinamica

Para calcular Fi basta ter armazenado as solucoes dos doissubproblemas Fi−1 e Fi−2. Logo, podemos reduzir a complexidadeespacial de Θ(n) para Θ(1).

Fib-PD-v2(n)

if n == 0return 0

if n == 1return 1

back2 = 0back1 = 1for i = 2 to n

next = back1 + back2back2 = back1back1 = next

return next

11 / 56

Outro exemplo: Coeficientes binomiais

Cnk =

(nk

)= n!

k!(n−k)!(nk

)e o numero de combinacoes de n elementos k a k .

Por palavras mais simples: numero de maneiras distintas de escolhergrupos de k elementos a partir de um conjunto de n elementos.

Exemplo: Dado um conjunto de 10 alunos, quantos grupos distintosde 3 alunos se podem fazer? Resp:

(103

)= 10!

3!7! = 120

A aplicacao directa da formula pode facilmente dar um overflowaritmetico por causa dos factoriais, mesmo que o resultado final caibaperfeitamente num inteiro.

12 / 56

Page 7: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Coeficientes binomiais (cont.)

Podemos definir(nk

)de modo recursivo.(n

k

)=(n−1k−1)

+(n−1

k

)I 1a parcela: k-esimo elemento pertence ao grupo⇒ e necessario escolher k − 1 dos restantes n − 1 elementos.

I 2a parcela: k-esimo elemento nao pertence ao grupo⇒ e necessario escolher k dos restantes n − 1 elementos.

Casos base: k = 0, n = k ⇒(nk

)= 1

13 / 56

Algoritmo naive (de forca bruta)

Comb(n, k)

if k == 0 or n == kreturn 1

elsereturn Comb(n − 1, k − 1) + Comb(n − 1, k)

14 / 56

Page 8: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Solucao com Programacao Dinamica

Comb-PD(n, k)

for i = 0 to nfor j = 0 to min(i , k)

if j == 0 or j == iA[i , j ] = 1

else A[i , j ] = A[i − 1, j − 1] + A[i − 1, j ]return A[n, k]

15 / 56

Exemplo de execucao: Comb-PD(5,3)

ij

0 1 2 3

0 11 1 12 1 2 13 1 3 3 14 1 4 6 45 1 5 10 10

16 / 56

Page 9: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Memoization

E uma tecnica semelhante a Programacao Dinamica.

Mantem o algoritmo recursivo na forma top-down.

A ideia e inicializar as solucoes dos subproblemas com o valor“Desconhecido”.

Depois, quando queremos resolver um subproblema, verificamosprimeiro se ja foi resolvido.

I Se sim, retornamos a solucao previamente armazenada.

I Se nao, resolvemos o subproblema e armazenamos a solucao.

Cada subproblema so e resolvido uma vez.

17 / 56

Versao memoized de Comb

Comb-Memoized(n, k)

for i = 0 to nfor j = 0 to min(i , k)

C [i , j ] = unknownreturn M-Comb(n, k)

M-Comb(i , j)

if C [i , j ] == unknownif j == 0 or j == i

C [i , j ] = 1else C [i , j ] = M-Comb(i − 1, j − 1) + M-Comb(i − 1, j)

return C [i , j ]

18 / 56

Page 10: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Outro exemplo: cortar tubos (rod cutting)

Problema: Dado um tubo de comprimento n e uma tabela com precospi para pedacos de tubo de comprimento i (i = 1, 2, . . n), determinaro valor maximo de receita rn que se pode obter se podermos cortar otubo em pedacos e vende-los separadamente, assumindo que os cortessao gratuitos e os comprimentos dos pedacos de tubo sao numerosinteiros.

Exemplo: n = 4

length i 1 2 3 4

price pi 1 5 8 9

19 / 56

8 maneiras de cortar

20 / 56

Page 11: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Melhor solucao: cortar em 2 pedacos de comprimento 2. Receita totale 5 + 5 = 10.

Para cada i = 1 . . n − 1, cortamos ou nao cortamos =⇒ 2n−1

maneiras de cortar o tubo.

21 / 56

Sub-estrutura optima

Vamos tentar definir a solucao optima em termos de solucoes optimasde subproblemas.

Seja ri a receita maxima para um tubo de comprimento i .

Entao rn sera o maximo de:I pnI r1 + rn−1

I r2 + rn−2

I . . .I rn−1 + r1

22 / 56

Page 12: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Uma decomposicao mais simples

Toda a solucao optima tem um pedaco “mais a esq.”(potencialmentede comprimento n no caso de nao haver qualquer corte).

A receita total vai ser o custo desse pedaco mais o custo da melhorreceita que se consegue obter com cortes no pedaco de tubo quesobrar.

rn e o maximo de:I p1 + rn−1

I p2 + rn−2

I . . .I pn + r0

23 / 56

Pseudocodigo

Cut-Rod(p, n)

if n == 0return 0

q = −∞for i = 1 to n

q = max(q, p[i ] + Cut-Rod(p, n − i))return q

E muito ineficiente, tal como nos algoritmos de forca-bruta para osnumeros de Fibonacci e para as Combinacoes.

24 / 56

Page 13: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Arvore de chamadas recursivas de Cut-Rod com n = 4Calcula o mesmo subproblema vezes sem fim.

Complexidade: Θ(2n).

25 / 56

Abordagem com programacao dinamica

Resolver cada subproblema apenas uma vez, e armazenar o resultadopara uso futuro.

Fazer uma abordagem bottom-up: resolver primeiro os subproblemasmais pequenos.

Quando necessitamos de resolver um subproblema maior, usamos osresultados (ja calculados) dos subproblemas mais pequenos.

26 / 56

Page 14: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Algoritmo de programacao dinamica

Bottom-Up-Cut-Rod(p, n)

Let r [0 . . n] be a new arrayr [0] = 0for j = 1 to n

q = −∞for i = 1 to j

q = max(q, p[i ] + r [j − i ])r [j ] = q

return r [n]

27 / 56

28 / 56

Page 15: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Complexidade temporal

Dois ciclos encadeados que dependem linearmente de n, e tempoconstante em cada iteracao. Complexidade temporal e Θ(n2).

Passamos de tempo exponencial para tempo polinomial.

29 / 56

Reconstrucao da solucaoO algoritmo retorna o valor da solucao optima, mas nao a solucao.

Podemos obter a solucao com a seguinte modificacao: s[i ] guarda otamanho do pedaco de tubo mais a esquerda da solucao optima deum problema rod-cut de comprimento i .

Extended-Bottom-Up-Cut-Rod(p, n)

Let r [0 . . n] and s[0 . . n] be new arraysr [0] = s[0] = 0for j = 1 to n

q = −∞for i = 1 to jif p[i ] + r [j − i ] > q

q = p[i ] + r [j − i ]s[j ] = i

r [j ] = qreturn r and s

30 / 56

Page 16: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Reconstrucao da solucao

i 0 1 2 3 4

r [i ] 0 1 5 8 10s[i ] 0 1 2 3 2

Print-Cut-Rod-Solution(p, n)

(r , s) = Extended-Bottom-Up-Cut-Rod(p, n)while n > 0

print s[n]n = n − s[n]

31 / 56

Memoization

Uma tecnica semelhante a Programacao Dinamica.

Mantem o algoritmo na forma recursiva (top-down).

A ideia e usar uma flag para indicar se um subproblema ja estaresolvido.

Depois, para resolver um subproblema temos de primeiro verificar seja foi resolvido.

I Se sim, basta retornar a solucao previamente armazenada.

I Se nao, resolvemos o subproblema e guardamos a solucao para usofuturo.

Cada subproblema so e resolvido uma vez.

32 / 56

Page 17: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Verao memoized de Cut-Rod

Memoized-Cut-Rod(p, n)

Let r [0 . . n] be a new arrayfor i = 0 to n

r [i ] = −∞return Memoized-Cut-Rod-Aux(p, n, r)

Memoized-Cut-Rod-Aux(p, n, r)

if r [n] ≥ 0return r [n]

if n == 0q = 0

else q = −∞for i = 1 to n

q = max(q, p[i ] + Memoized-Cut-Rod-Aux(p, n − i , r))r [n] = qreturn q

33 / 56

Complexidade temporal

Cada subproblema so e resolvido uma vez.

Os subproblems tem tamanho 0, 1, . . . , n, e requerem um ciclo forsobre o seu tamanho

Complexidade tambem e Θ(n2).

34 / 56

Page 18: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Outro exemplo: Longest Common Subsequence (LCS)

Dadas duas sequencias, X = x1x2 . . . xm e Y = y1y2 . . . yn, encontraruma subsequencia comum a X e Y que seja o mais longa possıvel.

Exemplo:

I X = n o c t u r n o

I Y = m o s q u i t e i r o

I LCS(X ,Y ) = o t r o (tambem podia ser o u r o)

35 / 56

Algoritmo de forca bruta

Gerar todas as subsequencias de X e verificar se tambem esubsequencia de Y , e ir guardando a subsequencia mais longa vistaate ao momento.

Complexidade?

I Θ(2m)→ para gerar todas as subsequencias de X .

I Θ(n)→ para verificar se uma subsequencia de X e subsequencia de Y .

I Total: Θ(n 2m)

I E exponencial. Muito mau!

36 / 56

Page 19: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Sera que podemos aplicar Programacao Dinamica?

Se sim teremos de conseguir definir o problema recursivamente emtermos de subproblemas.

O no de subproblemas tem de ser relativamente pequeno (polinomialem n e m) para que a Programacao Dinamica seja util.

Depois de definir o problema em termos de subproblemas, podemosresolver o problema de baixo para cima, comecando pelos casos basee armazenando as solucoes dos subproblemas.

37 / 56

Subestrutura optima

Vamos olhar para prefixos de X e Y .

Seja Xi o prefixo dos i primeiros elementos de X .

Exemplo: X = n o c t u r n o

I X4 = n o c t

I X0 = ∅I X3 = n o c

I X8 = n o c t u r n o

38 / 56

Page 20: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Subestrutura optima

Seja X = x1x2 . . . xm e Y = y1y2 . . . yn.

Seja Z = z1z2 . . . zk uma LCS entre X e Y .

Tres casos:

1 Se xm = yn, entao zk = xm = yn e Zk−1 e uma LCS entre Xm−1 e Yn−1.

2 Se xm 6= yn e zk 6= xm, entao Z e uma LCS entre Xm−1 e Yn.

3 Se xm 6= yn e zk 6= yn, entao Z e uma LCS entre Xm e Yn−1.

39 / 56

Demonstracao do caso 1

Caso 1: Se xm = yn, entao zk = xm = yn e Zk−1 e uma LCS entre Xm−1 eYn−1.

Teremos de provar que zk = xm = yn. Suponhamos que tal nao everdade. Entao a subsequencia Z ′ = z1z2 . . . zkxm e umasubsequencia comum a X e Y e tem comprimento k + 1.

I ⇒ Contradiz o facto de Z ser uma LCS entre X e Y .

40 / 56

Page 21: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Demonstracao do caso 1 (cont.)

Agora temos de provar que Zk−1 e uma LCS entre Xm−1 e Yn−1.Suponhamos que existe uma subsequencia W comum a Xm−1 e Yn−1que e mais longa que Zk−1.

I ⇒ comprimento de W ≥ k.

A subsequencia W ′ = W || xm e comum a X e Y e tem comprimento≥ k + 1.

I Contradiz o facto de Z ser uma LCS entre X e Y .

41 / 56

Demonstracao dos casos 2 e 3

Caso 2: Se xm 6= yn e zk 6= xm, entao Z e uma LCS entre Xm−1 e Yn.

Suponhamos que existe uma subsequencia W comum a Xm−1 e Yn

com comprimento > k . Entao W e uma subsequencia comum entreX e Y .

I =⇒ Contradiz o facto de Z ser uma LCS entre X e Y .

Caso 3: Se xm 6= yn e zk 6= yn, entao Z e uma LCS entre Xm e Yn−1.

A demonstracao do caso 3 e analoga a do caso 2.

42 / 56

Page 22: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Resumindo

Podemos definir LCS(Xm,Yn) em termos de subproblemas.

LCS(Xm,Yn) =

∅ , se m = 0 ou n = 0

LCS(Xm−1,Yn−1) || xm , se xm = yn

LCS(Xm−1,Yn) ouLCS(Xm,Yn−1) , se xm 6= yn

43 / 56

Comprimento de LCS(X ,Y )

Vamos tentar primeiro resolver um problema mais simples: Obter|LCS(X ,Y )| → o comprimento de LCS(X ,Y )

Seja c[i , j ] = |LCS(Xi ,Yj)|

Queremos obter c[m, n]

44 / 56

Page 23: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Definicao recursiva de c[i , j ]

c[i , j ] =

0 , se i = 0 ou j = 0

c[i − 1, j − 1] + 1 , se i , j > 0 e xi = yj

max(c[i − 1, j ], c[i , j − 1]) , se i , j > 0 e xi 6= yj

45 / 56

Algortimo recursivo

LCS-Length-Rec(X ,Y , i , j)

if i == 0 or j == 0return 0

elseif X [i ] == Y [j ]return LCS-Length-Rec(X ,Y , i − 1, j − 1) + 1

else a = LCS-Length-Rec(X ,Y , i − 1, j)b = LCS-Length-Rec(X ,Y , i , j − 1)return max(a, b)

Chamada inicial: LCS-Length-Rec(X ,Y ,m, n)

Tal como em Fib-Rec e Comb-Rec, a arvore da origem a muitossubproblemas repetidos.

O algoritmo e exponencial. Mas o numero de subproblemas distintos= m · n.

46 / 56

Page 24: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Podemos usar Programacao Dinamica

LCS-Length-DP(X ,Y )

m = X . lengthn = Y . lengthfor i = 1 to m

c[i , 0] = 0for j = 0 to n

c[0, j ] = 0for i = 1 to m

for j = 1 to nif X [i ] == Y [j ]

c[i , j ] = c[i − 1, j − 1] + 1elseif c[i − 1, j ] ≥ c[i , j − 1]

c[i , j ] = c[i − 1, j ]else c[i , j ] = c[i , j − 1]

return c[m, n]

47 / 56

Demo

c[i , j ] e preenchida linha a linha, da esquerda para a direita.

48 / 56

Page 25: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Como obter a LCS propriamente dita?

O nosso algoritmo apenas obteve o comprimento da LCS.

A ideia e alterar o codigo de LCS-Length-DP e, de cada vez queobtemos um c[i , j ], registamos como e que ele foi obtido.

Isso permite-nos reconstruir a solucao.

49 / 56

Aqui vai o codigo alterado

LCS-Length-DP-v2(X ,Y )

...for i = 1 to m

for j = 1 to nif X [i ] == Y [j ]

c[i , j ] = c[i − 1, j − 1] + 1b[i , j ] = “ ”

elseif c[i − 1, j ] ≥ c[i , j − 1]c[i , j ] = c[i − 1, j ]b[i , j ] = “ ↑ ”

else c[i , j ] = c[i , j − 1]b[i , j ] = “← ”

return c[m, n] , b

50 / 56

Page 26: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Demo

As setas ↑, ← e sao armazenadas em b[i , j ].b[i , j ] indica o subproblema escolhido para obter c[i , j ].

51 / 56

Uma vez tendo a informacao em b, podemos obter uma LCS entre Xe Y .

A chamada inicial e Print-LCS(b,X ,m, n)

Print-LCS(b,X , i , j)

if i == 0 or j == 0return // Nao faz nada

if b[i , j ] == “ ”Print-LCS(b,X , i − 1, j − 1)print X [i ]

elseif b[i , j ] == “ ↑ ”Print-LCS(b,X , i − 1, j)

elsePrint-LCS(b,X , i , j − 1)

52 / 56

Page 27: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

Complexidade

A complexidade e Θ(m · n)

A Programacao Dinamica reduziu a complexidade de exponencialpara polinomial.

No livro tem mais exemplos de problemas resolvidos comProgramacao Dinamica.

53 / 56

Versao memoized de LCS-Length

LCS-Length-Memoized(X ,Y )

m = X . lengthn = Y . lengthfor i = 0 to m

for j = 0 to nc[i , j ] = unknown

return M-LCS-Length(X ,Y ,m, n)

54 / 56

Page 28: Programa˘c~ao Din^amicaFibonacci: Algoritmo de Programa˘c~ao Din^amica Para calcular F i basta ter armazenado as solu˘c~oes dos dois subproblemas F i 1 e F i 2. Logo, podemos reduzir

M-LCS-Length(X ,Y , i , j)

if c[i , j ] == unknownif i == 0 or j == 0

c[i , j ] = 0elseif X [i ] == Y [j ]

c[i , j ] = M-LCS-Length(X ,Y , i − 1, j − 1) + 1else a = M-LCS-Length(X ,Y , i − 1, j)

b = M-LCS-Length(X ,Y , i , j − 1)c[i , j ] = max(a, b)

return c[i , j ]

55 / 56

Como aplicar a Programacao Dinamica?

Para aplicarmos Programacao Dinamica ou Memoization para resolver umproblema, temos de fazer 4 coisas:

1 Caracterizar a estrutura de uma solucao optima.

2 Definir o valor da solucao optima recursivamente em termos desubsolucoes optimas.

3 Calcular o valor de uma solucao optima de baixo para cima (no casode P.D.) ou de cima para baixo (no caso de Memoization).

4 Obter a solucao optima atraves da informacao calculada earmazenada no passo 3.

56 / 56