Programação Dinâmica
Técnicas de Projeto de Algoritmos Aula 13
Alessandro L. Koerich
Pontifícia Universidade Católica do Paraná (PUCPR)
Ciência da Computação – 7oPeríodo
Engenharia de Computação – 5oPeríodo
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 2 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Introdução
Programa do PA
Técnicas de Projeto de Algoritmos Fundamentos da Análise da Eficiência de Algoritmos 1. Resolução de Problemas e Tipos de Problemas 2. Fundamentos 3. Notação Assintótica e Classe de Eficiência 5. Análise Empírica de Algoritmos 6. Força Bruta 7. Dividir & Conquistar4. Análise Matemática de Algoritmos
8. Decrementar & Conquistar 9. Transformar & Conquistar
11. Programação Dinâmica 12. Estratégia Gulosa 13. Backtracking & Branch and Bound 14. Algoritmos Aproximados Limitações 15. Teorema do Limite Inferior 16. Árvores de Decisão 17. Problemas P, NP e NPC 10. Compromisso Tempo-Espaço
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 3 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Aulas Anteriores
Estratégia Força Bruta
Estratégia Dividir & Conquistar
Estratégia Reduzir & Conquistar
Estratégia Transformar & Conquistar
Estratégia Compromisso Tempo–Espaço
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 4 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Técnicas Avançadas de Projeto
Programação Dinâmica
Algoritmos Gulosos (Greedy)
Algoritmos Aproximados
Plano de Aula
Introdução
Programação de Linha de Montagem
Exemplo: Multiplicação de Cadeias de Matrizes
Subseqüência Comum Mais Longa
Elementos da Programação Dinâmica
Resumo
Introdução
A programação dinâmica se aplica
tipicamente a problemas de otimização onde uma série de escolhas deve ser feita, a fim de se alcançar um solução ótima
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 7 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Introdução
Resolve problemas combinando as soluções de
subproblemas
Aplicado quando os subproblemas não são
independentes, isto é, quando os
subproblemas compartilham subsubproblemas.
Resolve cada subsubproblema somente uma
vez e grava a resposta em uma tabela, evitando assim o trabalho de recalcular a resposta toda a vez que o subsubproblema é encontrado
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 8 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Introdução
Em geral, a programação dinâmica é aplicada
em problemas de otimização.
Problemas de otimização Muitas soluções possíveis; Cada solução tem um valor;
Desejamos encontrar uma solução com um valor
ótimo (min ou máx).
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 9 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Introdução
O desenvolvimento de um algoritmo de
programação dinâmica pode ser desmembrado em:
Caracterizar a estrutura de uma solução ótima Definir recursivamente o valor de uma solução ótima Calcular o valor de uma solução ótima em um
processo bottom–up
Construir uma solução ótima a partir de informações
calculadas
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 10 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Introdução
Usaremos a programação dinâmica para
resolver alguns problemas de otimização.
Primeiro exemplo: programação de duas
linhas de montagem
Programação de Linha de Montagem
Uma fábrica de automóveis com duas linhas de
montagem
Um chassis entra em cada linha de montagem
Peças são adicionadas a ele em uma série de estações
O automóvel sai pronto no final da linha
Programação de Linha de Montagem
Cada linha tem n estações numeradas com
j=1,2,3,...,n
Indicamos a j–ésima estação na linha i por Si,j. A j–ésima estação da linha 1 (S1,j) executa a mesma
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 13 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Porém, as estações foram construídas em
épocas diferentes e com tecnologias diferentes, assim, o tempo exigido em cada estação varia.
Indicamos o tempo de montagem exigido na
estação Si,jpor ai,j.
Temos também eie xicomo os tempos para um
chassis entrar na linha de montagem i e sair concluído da linha de montagem i
respectivamente.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 14 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Normalmente, um chassis entra e sai de uma
mesma linha de montagem.
Porém, no caso de um pedido urgente, um
automóvel parcialmente concluído pode ser passado de uma linha de montagem a outra.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 15 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
O tempo para transferir um chassi da linha
de montagem idepois da passagem pela
estação Si,jé ti,j, onde i=1,2 e j=1,2,...,n–1
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 16 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Problema
Determinar que estações escolher na linha 1 e quais escolher na linha 2 de modo a minimizar o tempo total de passagem de um único
automóvel pela fábrica.
Programação de Linha de Montagem
O tempo total mais rápido resulta da escolha
das estações 1, 3 e 6 da linha 1 e das estações 2, 4 e 5 da linha 2.
Programação de Linha de Montagem
Como resolver o problema?
Força Bruta: enumerar todos os modos
possíveis e calcular quanto tempo cada um deles demora.
Existem 2nmaneiras possíveis de escolher
estações Æ Ω (2n) Æ impraticável para n
grande
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 19 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Etapa 1: A estrutura do caminho mais rápido
pela fábrica
Caracterizar a estrutura de uma solução ótima Considerar o modo mais rápido possível para
um chassis seguir desde o ponto de partida passando pela estação S1,j.
Se j = 1, fácil: determinar somente quanto tempo
demora para passar pela estação S1,j
Se j ≥ 2, há duas opções para obter S1,j:
Através de S1,j-1, e depois diretamente para S1,j Através de S2,j-1, e depois transferido para S1,j
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 20 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Supondo que o caminho mais rápido é através de S1,j-1
Observação chave: devemos ter pego um
caminho mais rápido a partir da entrada através de S1,j-1 nesta solução.
Se houvesse um caminho mais rápido através
de S1,j-1, nós o usaríamos para obter um caminho mais rápido através de S1,j
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 21 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Supondo agora que o caminho mais rápido é através de S2,j-1
Observação chave: Novamente, devemos ter
pego um caminho mais rápido a partir da entrada através de S2,j-1 nesta solução.
Se houvesse um caminho mais rápido através
de S2,j-1, nós o usaríamos para obter um caminho mais rápido através de S1,j
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 22 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Geralmente: Uma solução ótima para um problema (o caminho mais rápido através S1,j) contém dentro dele um solução ótima para subproblemas (o caminho mais rápido através S1,j-1ou S2,j-1)
Isto é → uma subestrutura ótima.
Programação de Linha de Montagem
Usar subestruturas ótimas para construir soluções ótimas para o problema a partir de soluções ótimas para subproblemas
O caminho mais rápido através de S1,jé tanto:
Caminho mais rápido através de S1,j-1, e depois
diretamente através de S1,j ou
Caminho mais rápido através de S2,j-1, transferência
da linha 2 para linha 1, e depois através S1,j
Programação de Linha de Montagem
Simetricamente. . .
O caminho mais rápido através de S2,jé tanto:
Caminho mais rápido através de S2,j-1, e depois
diretamente através de S2,j ou
Caminho mais rápido através de S1,j-1, transferência
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 25 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Portanto, para resolver problemas de encontrar um caminho mais rápido através de S1,je S2,j, resolver os subproblemas de encontrar um caminho mais rápido através de S1,j-1e S2,j-1.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 26 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Etapa 2: Solução Recursiva
Definir recursivamente o valor de uma solução
ótima em termos das soluções ótimas dos subproblemas
Subproblemas: encontrar o caminho mais
rápido pela estação j em ambas as linhas, para j = 1, 2, . . ., n.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 27 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Seja fi[j] = o tempo mais rápido possível para
levar um chassi desde o ponto de partida até a estação Si,j, onde i = 1, 2 e j = 1, 2, . . ., n.
Meta: f* = tempo mais rápido para levar um
chassi por todo o percurso na fábrica. f* = min ( f1[n]+x1, f2[n]+x2) onde f1[1]=e1+ a1,1 e f2[1]=e2+ a2,1
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 28 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Para j = 2, . . ., n:
f1[1] = min( f1[ j–1] + a1,j , f2[ j–1] + t2,j-1+ a1,j) f2[1] = min( f2[ j–1] + a2,j , f1[ j–1] + t1,j-1+ a2,j)
Programação de Linha de Montagem
Combinando as equações anteriores, obtemos
as equações recursivas: j se a t j– , f a j– f j se a e j f ,j ,j-,j ≥ + + + = + = 2 ) ] 1 [ ] 1 [ min( 1 ] [ 1 1 2 2 1 1 1 , 1 1 1 ≥ + + + = + = 2 ) ] 1 [ ] 1 [ min( 1 ] [ 2 1 1 1 2 2 1 , 2 2 2 f j– a , f j– t a se j j se a e j f ,j ,j-,j
Programação de Linha de Montagem
fi[j] fornece o valor de uma solução ótima. E se
quisermos construir uma solução ótima?
Definimos li[j] = # linha (1 ou 2) cuja estação
j–1 é usada em um caminho mais rápido pela estação Si,j. Onde i = 1, 2 e j = 2, 3, ..., n
l* = # linha cuja estação n é usada em um
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 31 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 32 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Vamos através do caminho ótimo dado pelos
valores de l (linhas sombreadas na figura anterior).
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 33 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Etapa 3: Cálculo dos Tempos mais Rápidos
(Computar uma solução ótima)
Poderíamos somente escrever um algoritmo
recursivo baseado nas recorrências anteriores.
Porém, seu tempo de execução é exponencial
em n.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 34 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Seja ri(j) o número de referências feitas a fi[j]
em um algoritmo recursivo
A partir da primeira equação temos:
r1(n) = r2(n) = 1
Pelas recorrências temos:
r1(j) = r2(j) = r1(j+1)+r2(j+1) para j = 1, 2, ..., n–1
Programação de Linha de Montagem
Assim, ri(j) = 2n-j
Prova: Indução sobre j, decrescente a partir de
n
Base: j = n, 2n–j = 20 = 1 = ri(n)
Passo de indução: Assumir ri(j+1) = 2n–(j+1)
Então, ri(j) = ri(j+1) + r2(j+1) = 2n–(j+1) + 2n–(j+1)
= 2n–(j+1)+1
= 2n–j → Θ(2n)
Programação de Linha de Montagem
Portanto, f1[1] sozinho é referenciado 2n-1vezes Portanto, top–down não é uma boa maneira de
computar fi[j].
Observação: Podemos fazer melhor. fi[j]
depende somente de f1[j – 1] e f2[j – 1] para j ≥ 2.
Portanto, a computação deve ser feita em
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 37 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
O procedimento Fast–Way toma como entrada
os valores (ai,j, ti,j, eie xi), bem como n, o
número de estações em cada linha de montagem.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 38 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 39 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Etapa 4: Construção do Caminho mais Rápido
pela Fábrica (Construindo uma solução ótima)
Após calculados fi[j], f*, li[j] e l*, podemos
construir a seqüência de estações usadas no caminho mais rápido pela fábrica.
Procedimento Print–Stations
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 40 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Programação de Linha de Montagem
Programação de Linha de Montagem
Procedimento Print–Stations
No exemplo da figura, teríamos: Linha 1: estação 6 Linha 2: estação 5 Linha 2: estação 4 Linha 1: estação 3 Linha 2: estação 2 Linha 1: estação 1
Resumo
Características da Programação Dinâmica: O problema precisa ter a propriedade da
subestrutura ótima
Então começamos com uma solução recursiva, mas
ela será inviável
Com isso, a transformamos em uma solução
iterativa, que irá ter tempo polinomial, com a característica de calcular primeiro o valor de uma solução ótima e só depois construir a solução.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 43 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Multiplicação de Cadeia de Matrizes
Problema: Recebemos uma seqüência (cadeia) < A1, A2, ..., An> de n matrizes a serem multiplicadas e
desejamos calcular o produto.
A1A2...An
Solução: Utilizar um algoritmo padrão para multiplicação de pares de matrizes.
Quais pares multiplicar? Em que ordem?
A multiplicação de matrizes é associativa, e assim, todas as colocações de parênteses resultam no mesmo
produto.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 44 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Multiplicação de Cadeia de Matrizes
Exemplo: Para a cadeia de matrizes < A1, A2, A3,
A4>, o produto A1A2A3A4pode ser
completamente colocado entre parênteses de cinco modos distintos:
( A1( A2( A3A4) ) ) ( A1( ( A2A3) A4) ) ( ( A1A2) ( A3A4) ) ( ( A1( A2A3) ) A4) ( ( ( A1A2) A3) A4)
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 45 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Multiplicação de Cadeia de Matrizes
Atenção!!! O modo como uma cadeia de
matrizes é colocada entre parênteses pode ter um impacto dramático sobre o custo de avaliação do produto.
Considere primeiro o custo de multiplicar duas
matrizes. O pseudo–código do algoritmo padrão é fornecido a seguir
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 46 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Multiplicação de Cadeia de Matrizes
Se A é uma matriz p x q e B é uma matriz q x r, a matriz resultante C é uma matriz p x r.
O tempo para calcular C é dominado pelo número de multiplicações escalares na linha 7, que é pqr.
Multiplicação de Cadeia de Matrizes
Exemplo: Considere o problema de uma cadeia
< A1A2A3> de três matrizes onde as dimensões são: 10 x 100, 100 x 5 e 5 x 50 respectivamente.
Se fizermos ((A1A2)A3)...
Se fizermos (A1(A2A3) )...
Multiplicação de Cadeia de Matrizes
O problema de multiplicação de cadeia de matrizes pode ser enunciado da forma a seguir:
Dada uma cadeia < A1,A2,..., An> de n matrizes
na qual , para i = 1, 2, ..., n, a matriz Aitem
dimensão pi–1pi, coloque completamente entre parênteses o produto A1A2...Ande um modo que
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 49 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Multiplicação de Cadeia de Matrizes
Contagem do número de colocações entre parênteses.
Sendo P(n) o número de alternativas para a colocação dos parênteses em uma seqüência de n matrizes.
A solução para a recorrência é Ω(2n) → força
bruta é uma estratégia não adequada.
≥ − = =
∑
− = 2 ) ( ) ( 1 1 ) ( 1 1 n se k n P k P n se n P n kCiência/Eng. de Computação Proj. Anal. Algoritmos 2004 50 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Multiplicação de Cadeia de Matrizes
Etapa 1: A estrutura de uma parentização ótima
Seja Ai...jpara a matriz que resulta da avaliação
do produto AiAi+1...Aj.
Para obter a solução do problema proposto,
devemos obter A1...n
que pode ser obtido pelo produto de A1...kAk+1...n
cujo custo ótimo é obtido pela soma do custo de A1...kcom Ak+1...nmais o custo do produto delas.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 51 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Multiplicação de Cadeia de Matrizes
Etapa 1: A estrutura de uma parentização ótima
A sub–cadeia A1..kdeve ter parentização ótima Do contrário poderíamos substituí–la por outra
com custo menor que o ótimo, o que é uma contradição.
Logo, uma solução ótima para uma instância do
problema contém soluções ótimas para as sub-instâncias do mesmo problema, o que permite o emprego da programação dinâmica.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 52 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Multiplicação de Cadeia de Matrizes
Etapa 2: Uma solução ótima recursiva
Definir um expressão recursiva em função das sub-instâncias.
Usaremos uma tabela m[i,j] 1 ≤ i ≤ j ≤ n, onde m é o número mínimo de multiplicações escalares necessárias para calcular a matriz Ai...j
m[i,i]=0 pois Ai...i= Ai, não havendo necessidade de qualquer cálculo.
Para i<j, podemos usar a estrutura ótima delineada no passo 1
Multiplicação de Cadeia de Matrizes
Etapa 2 (cont.): Uma solução ótima recursiva
Assim Ai..jpode ser dividido em duas partes: Ai...kAk+1...j, i ≤ k < j, e
m[i,j] é igual ao menor custo para calcular Ai...ke Ak+1...j, mais o custo para multiplicar essas duas matrizes. O custo para multiplicar Ai...kAk+1...jvale pi-1pkpj
multiplicações escalares. Desse modo obtemos:
m[i,j] = m[i,k] + m[k+1,j] + pi-1pkpj
Multiplicação de Cadeia de Matrizes
Etapa 2 (cont.): Uma solução ótima recursiva
A equação recursiva pressupõe que conhecemos o valor de k. Porém existem j–1 valores possíveis para k. A definição recursiva para o custo mínimo de colocar
entre parênteses o produto AiAi+1... Ajse torna:
.
{
}
< + + + = = j i se j i se j i m p p p j] 1, m[k k] m[i, min 0 ] , [ j k 1 -iCiência/Eng. de Computação Proj. Anal. Algoritmos 2004 55 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Multiplicação de Cadeia de Matrizes
Etapa 2 (cont.): Uma solução ótima recursiva
Como indicar uma parentização ótima?
O valor m[i,j] dá o custo ótimo, mas não informações para a construção de uma solução ótima
Basta armazenar na matriz s[i,j] o valor de k usado para o valor ótimo de m[i,j], ou seja
m[i,j] = m[i,k] + m[k+1,j] + pi-1pkpj
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 56 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Multiplicação de Cadeia de Matrizes
Etapa 3: Determinando a solução ótima
Em vez de calcular recursivamente a solução para a recorrência anterior, calculamos o custo ótimo usando uma abordagem tabular de baixo para cima.
Neste ponto deve-se elaborar um algoritmo para resolução do problema,
Fazendo os cálculos de tal forma que nenhuma solução seja requisitada antes que a mesma já tenha sido calculada
Usando a programação dinâmica passamos a ter Θ(n2) subproblemas
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 57 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Multiplicação de Cadeia de Matrizes
Etapa 3 (cont.): Determinando a solução ótima
O problema (preencher a tabela m) deve ser
resolvido em ordem crescente de comprimento da cadeia de matrizes
O que equivale a percorrer as diagonais
superiores da matriz de custo, a partir da diagonal maior.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 58 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Multiplicação de Cadeia de Matrizes
Multiplicação de Cadeia de Matrizes
L2 e L3: O algoritmo calcula primeiro m[i,i]=0 para i=1,2,...,n (custos mínimos para cadeias de
comprimento 1)
L4 a L12: Usa a recorrência para calcular m[i,i+1] para i=1,2,...,n–1 (custos mínimos para cadeias de
comprimento 2)
Na segunda passagem através do loop, ele calcula m[i,i+2] para i=1,2,...,n–2 (custos mínimos para
cadeias de comprimento 3) e assim por diante. Em cada etapa, o custo m[i,j] calculado em L9 e L12,
depende apenas de m[i,k] e m[k+1,j] já calculadas.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 61 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Multiplicação de Cadeia de Matrizes
O tempo de execução de Matrix–Chain–Order
é O(n3).
Os loops estão aninhados com profundidade
três e cada índice de loop (l,i,k) toma no máximo n valores.
Assim, Matrix–Chain–Order é muito mais
eficiente que o método de força bruta (tempo exponencial)
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 62 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Multiplicação de Cadeia de Matrizes
Etapa 4: Construção da solução ótima
Matrix-Chain-Order determina somente o número ótimo de multiplicações escalares necessárias para calcular um produto de cadeias de matrizes. Ele não mostra diretamente como multiplicar as
matrizes.
A solução ótima é calculada a partir das informações armazenadas na tabela s[1...n,1...n]
Cada entrada s[i,j] registra o valor de k tal que a colocação ótima dos parenteses de AiAi+1...Ajdivide o
produto entre Ake Ak+1.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 63 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Multiplicação de Cadeia de Matrizes
Para o exemplo anterior Print–Optimal–
Parens produz ((A1(A2A3)) ((A4A5)A6))
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 64 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Elementos da Programação Dinâmica
Quando aplicar um método de programação
dinâmica?
Ingredientes fundamentais que um problema
de otimização deve ter para que a programação dinâmica seja aplicável:
Subestrutura ótima
Subproblemas sobrepostos
Elementos da Programação Dinâmica:
Subestrutura Ótima
Mostrar que a solução para um problema consiste em fazer um escolha, a qual deixa um ou mais
subproblemas para resolver.
Suponha que seja dada uma última escolha que leve a uma solução ótima
Dada esta escolha, determinar quais subproblemas surgem e como caracterizar o espaço resultante de subproblemas
Mostrar que as soluções para subproblemas usadas dentro de uma solução ótima devem ser também ótimas. Usar geralmente cut–and–paste
Elementos da Programação Dinâmica:
Subestrutura Ótima
Usar geralmente cut–and–paste:
Suponha que uma das soluções dos subproblemas
não seja ótima
Corte–a fora
Cole no lugar uma solução ótima
Obtenha uma melhor solução para o problema
original. Contradiz a otimalidade da solução do problema.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 67 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Elementos da Programação Dinâmica:
Subestrutura Ótima
Como caracterizar o espaço dos subproblemas?
Manter o espaço o mais simples possível? Expandi–lo quando necessário
Exemplos:
Programação de uma linha de montagem Espaço de subproblemas era a maneira mais rápida
a partir da entrada e através das estações S1,je S2,j
Não há necessidade de tentar um espaço mais geral
de subproblemas
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 68 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Elementos da Programação Dinâmica:
Subestrutura Ótima
Subestrutura ótima varia através dos domínios dos problemas.
1. Quantos subproblemas são usados em um solução ótima?
2. Quantas escolhas para determinar qual subproblema utilizar?
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 69 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Elementos da Programação Dinâmica:
Subestrutura Ótima
Programação da linha de montagem
1 subproblema
2 escolhas (para Si,j, usar S1,j-1ou S2,j-1)
Subseqüência Comum mais Longa (LCS)
1 subproblema e:
1 escolha ( se xi=yi, LCS de Xi-1e Yj-1), ou
2 escolhas ( se xi≠yi, LCS de Xi-1e Y, e LCS de X e Yj-1)
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 70 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Elementos da Programação Dinâmica:
Subestrutura Ótima
Informalmente, o tempo de execução depende (número de subproblemas) vezes (número de escolhas)
Programação da linha de montagem: Θ (n)
subproblemas, 2 escolhas para cada ⇒ tempo de execução Θ (n)
Subseqüência comum mais longa: Θ (mn)
subproblemas, ≤ 2 escolhas para cada ⇒ tempo de execução Θ (mn)
Elementos da Programação Dinâmica:
Subestrutura Ótima
Programação Dinâmica usa subestrutura ótima
bottom–up.
Primeiro, encontrar soluções ótimas para subproblemas Então, escolher a qual utilizar em uma solução ótima
para o problema.
Quando estudarmos algoritmos gulosos, veremos que eles funcionam top–down, primeiro fazendo uma escolha que pareça melhor e então resolvendo os subproblemas resultantes.
Elementos da Programação Dinâmica:
Subestrutura Ótima
Não se engane pensando que subestruturas ótimas se aplicam a todos os problemas de otimização.
Ex: Dois problemas que parecem similares. Em ambos, são dados grafos diretos não
ponderados G = (V,E), onde:
V é um conjunto de vértices
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 73 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Elementos da Programação Dinâmica:
Subestrutura Ótima
Encontre um caminho (seqüência de arestas conectadas) do vértice u ao vértice v.
Caminho mais curto: encontrar o caminho u →v
com menos arestas. Deve ser simples (sem ciclos) pois removendo um ciclo de um caminho temos um caminho com menos arestas;
Caminho simples mais longo: encontrar um caminho
simples u →v com mais arestas.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 74 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Elementos da Programação Dinâmica:
Subestrutura Ótima
O caminho mais curto tem subestrutura ótima
Suponha que p é o caminho mais curto u →v. Seja w qualquer vértice sobre p.
Seja p1uma porção de p, u →w.
Então, p1é um caminho mais curto u →w.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 75 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Elementos da Programação Dinâmica:
Subestrutura Ótima
Prova: Suponha que exista um caminho mais curto p’
1u →v. Cortar p1, substituí–lo por p’1e obter o caminho u →w →v com menos arestas que p.
Portanto, podemos encontrar o caminho mais
curto u →v considerando todos os vértices intermediários w e então encontrando os caminhos mais curtos u →w e w →v.
O mesmo argumento se aplica a p2
p’1 p2
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 76 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Elementos da Programação Dinâmica:
Subestrutura Ótima
O caminho mais longo tem uma subestrutura ótima?
Parece que sim Mas ele não tem !!
Elementos da Programação Dinâmica:
Subestrutura Ótima
Considere q →r →t = caminho mais longo entre q e t. Os seus subcaminhos são os subcaminhos mais longos?
Não!!!
Subcaminho entre q e r é q →r.
Caminho simples mais longo entre q e r é q→s→t→r Subcaminho entre r e t é r →t.
Caminho simples mais longo entre r e t é r→q→s→t
Elementos da Programação Dinâmica:
Subestrutura Ótima
Além de não existir uma subestrutura ótima, não podemos montar uma solução legal a partir da solução para subproblemas.
Combinar caminho mais longos simples: q →s →t →r →q →s →t Não é simples!!!
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 79 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Elementos da Programação Dinâmica:
Subestrutura Ótima
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 80 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Elementos da Programação Dinâmica:
Subestrutura Ótima
Qual é a grande diferença entre o caminho mais longo e o caminho mais curto?
O caminho mais curto tem subproblemas independentes A solução para um subproblema não afeta a solução de outro
subproblema do mesmo problema
Caminho simples mais longo: subproblemas não são independentes
Considere subproblemas do caminho simples mais longo: q→r e r→t.
O caminho simples mais longo q→r utiliza s e t.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 81 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Elementos da Programação Dinâmica:
Subestrutura Ótima
Qual é a grande diferença entre o caminho mais longo e o caminho mais curto (cont.)?
Não podemos utilizar s e t para resolver o caminho
simples mais longo r→t, pois se o fizermos, o
caminho não será simples.
Mas temos que utilizar t para encontrar o caminho
simples mais longo r→t.
Utilizando recursos (vértices) para resolver um
subproblema torná–os indisponíveis para resolver outros subproblemas.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 82 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Elementos da Programação Dinâmica:
Subestrutura Ótima
Subproblemas independentes:
Linha de montagem e Subseqüência comum mais
longa:
1 subproblema ⇒ automáticamente independente
Elementos da Programação Dinâmica:
Subproblemas Sobrepostos
Subproblemas sobrepostos
O segundo ingrediente que um problema de
otimização deve ter para a programação dinâmica ser aplicável.
O espaço de subproblemas deve ser pequeno .
Elementos da Programação Dinâmica:
Subproblemas Sobrepostos
Subproblemas sobrepostos
ocorrem quando um algoritmo recursivo revisita o
mesmo problema repetidamente
Bons algoritmos “dividir e conquistar” geralmente
geram um novo problema em cada estágio da recursão.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 85 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Elementos da Programação Dinâmica:
Subproblemas Sobrepostos
Exemplo: Multiplicação de Cadeia de Matrizes.
Matrix–Chain–Order procura repetidamente a
solução para subproblemas em linhas inferiores quando resolve problemas em linhas superiores.
Ex: a entrada m[3,4] é referenciada 4 vezes: durante
o cálculo de m[2,4], m[1,4], m[3,5] e m[3,6].
Comparar com o procedimento recursivo.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 86 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Elementos da Programação Dinâmica:
Subproblemas Sobrepostos
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 87 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Elementos da Programação Dinâmica:
Subproblemas Sobrepostos
Recursivo: Ω(2n)
Programação Dinâmica: O(n2)
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 88 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Elementos da Programação Dinâmica:
Memoização
Método Alternativo: Memoization
“Armazene, não recompute”
Faça uma tabela indexada por subproblemas Quando resolver um subproblema:
Buscar na tabela
Se a resposta for sim, use–a
Senão, compute a resposta e armazene–a
Em programação dinâmica, vamos um passo
adiante. Determinamos em que ordem queremos acessar a tabela e preenchemos desta maneira.
Memoização
Subsequência Comum Mais Longa
Problema: Dadas duas sequências, X=<x1, x2,
..., xm> e Y=<y1,y2,...yn>, encontrar a subsequência comum a ambas cujo comprimento seja o mais longo.
Uma subsequência não precisa ser consecutiva
(contínua), mas ela deve estar em ordem.
O problema da LCS pode se resolvido por força
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 91 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Subsequência Comum Mais Longa
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 92 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Subsequência Comum Mais Longa
Algoritmo “Força–Bruta”Para cada subseqüência de X, verificar se é uma
subseqüência de Y.
Tempo: Θ ( n 2m)
2msubseqüências de X para verificar
Cada subseqüência leva Θ (n) para verificar. Varrer Y
para a primeira letra, a partir dela, varrer pela segunda letra, e assim por diante.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 93 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Subsequência Comum Mais Longa
Etapa 1: Caracterização de uma Subseqüência Comum mais Longa
Algoritmo “Força–Bruta”: Para cada subseqüência de X, verificar se é uma subseqüência de Y.
Cada subseqüência de X corresponde a um subconjunto dos índices {1,2,..., m} de X. Existem 2msubseqüências
de X.
Tempo: Θ ( n 2m)
2msubseqüências de X para verificar
Cada subseqüência leva Θ (n) para verificar. Varrer Y para a primeira letra, a partir dela, varrer pela segunda letra, e assim por diante.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 94 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Subsequência Comum Mais Longa
Etapa 1 (cont.)Porém o problema da LCS tem uma
propriedade de subestrutura ótima.
Dada uma seqüência X = < x1,x2,...,xm>,
definimos o i–ésimo prefixo de X, para i=0,1,...,m como Xi=< x1,x2,...,xi>.
Ex: Se X = < A, B, C, B, D, A, B>, então X4= <
A, B, C, B > e X0é a seqüência vazia.
Subsequência Comum Mais Longa
Etapa 1 (cont.)
Sejam as seqüências X = < x1,x2,...,xm> e Y = <
y1,y2,...,ym> e seja Z = < z1,z2,...,zm> qualquer LCS de X
e Y. Notação:
Xi= prefixo <x1,...,xi>
Yi= prefixo <y1,...,yi> Teorema:
Seja Z = <z1,...,zk> qualquer LCS de X e Y.
1. Se xm=yn, então zk=xme Zk–1é uma LCS de Xm–1e Yn–1.
2. Se xm≠yn, então zk≠xm⇒ Z é uma LCS de Xm–1e Y.
3. Se xm≠yn, então zk≠yn⇒ Z é uma LCS de X e Yn–1.
Subsequência Comum Mais Longa
Etapa 1 (cont.) Prova:
1. Primeira mostrar que zk=xm=yn. Suponha que não. Então, faça uma
subseqüência Z’= <z1,...,zk, xm>. É uma subseqüência comum de X e
Y e tem comprimento k + 1 ⇒ Z’ é uma subseqüência comum mais
longa que Z ⇒ contradiz Z sendo uma LCS.
Agora mostrar que Zk+1é uma LCS de Xm–1e Yn–1. Claramente, é
uma subseqüência comum. Agora suponha que existe uma subseqüência comum W de Xm–1e Yn–1 que é mais longa que Zk+1⇒
comprimento de W ≥ k. Faça a subseqüência W’ anexando xma W.
W’ é uma subseqüência comum de X e Y, tem comprimento ≥ k+1
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 97 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Subsequência Comum Mais Longa
Etapa 1 (cont.) Prova (cont.):
2. Se zk≠xm, então Z é uma subseqüência comum de Xm–1e Y. Suponha que exista uma subseqüência W de Xm–1e Y
com comprimento > k. Então W é uma subseqüência comum de X e Y ⇒ contradiz Z sendo uma LCS. 3. Simétrica a 2.
Portanto, uma LCS de duas seqüências contém como um prefixo uma LCS de prefixos das seqüências.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 98 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Subsequência Comum Mais Longa
Etapa 2 : Formulação Recursiva
Do teorema anterior, temos que existem 1 ou 2
subproblemas a examinar quando se encontra uma LCS de X = < x1,x2,...,xm> e Y = < y1,y2,...,ym>
Se xm=yn, devemos encontrar uma LCS de Xm–1e Yn–1. Se xm≠yn, devemos resolver 2 subproblemas:
Encontrar uma LCS de Xm–1e Y.
Encontrar uma LCS de X e Yn–1.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 99 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Subsequência Comum Mais Longa
Etapa 2 (cont.): Formulação Recursiva
A solução recursiva para o problema da LCS envolve estabelecer uma recorrência para o valor de uma solução ótima.
Definindo c [ i,j ] = comprimento da LCS de Xie Yj. Se i=0 ou j=0,
uma das seqüencias tem comprimento 0, logo LCS = 0.
A subestrutura ótima do problema da LCS fornece a fórmula recursiva: . ≠ > = > + − − = = = j i j i y x e j i se j– i ,c j i– c y x e j i se j i c j i se j i c 0 , ]) 1 , [ ] , 1 [ max( 0 , 1 ] 1 , 1 [ 0 ou 0 0 ] , [
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 100 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Subsequência Comum Mais Longa
Etapa 3: Calculando o Comprimento da LCSO procedimento LCS–LENGTH toma duas
seqüencias X e Y como entradas.
Armazena os valores de c[i,j] em uma tabela
c[0...m,0...n].
Mantém uma tabela b[1...m,1...n] para construir
a solução ótima. b[i,j] aponta para a entrada da tabela correspondente à solução ótima do subproblema escolhida ao se calcular c[i,j].
Subsequência Comum Mais Longa
Etapa 3(cont.): Cálculo do comprimento da solução ótima
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 103 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Subsequência Comum Mais Longa
Etapa 4: Cálculo do comprimento da soluçãoótima
A chamada inicial é PRINT–LCS (b,X,m,n) b[i,j] aponta para a entrada da tabela cujo
subproblema usamos para resolver LCS de Xie
Yj.
Quando b[i,j] = É, estendemos LCS em um
caractere. Então a subseqüência comum mais longa = entradas contendo É.
Ciência/Eng. de Computação Proj. Anal. Algoritmos 2004 104 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Subsequência Comum Mais Longa
Construção de uma LCSCiência/Eng. de Computação Proj. Anal. Algoritmos 2004 105 Alessandro L. Koerich (alekoe@ppgia.pucpr.br)
Resumo
Características da Programação Dinâmica:
O problema precisa ter a propriedade da
subestrutura ótima
Então começamos com uma solução recursiva,
mas ela será inviável
Com isso, a transformamos em uma solução
interativa, que irá ter tempo polinomial, com a característica de calcular primeiro o valor de uma solução ótima e só depois construir a solução.