Complexidade de Algoritmo
Técnicas de Projeto de Algoritmo
Prof. Samuel Lemes
Programação Dinâmica
Resolve problemas combinando as soluções dos Sub-problemas (igual ao D & C).
Aplicável quando os subproblemas não são
independentes, ou seja, compartilham
subsubproblemas.
Dividir & Conquistar, neste contexto, não é eficiente.
Programação Dinâmica resolve cada subproblema uma só vez e então grava sua resposta em uma tabela.
Programação Dinâmica
Exemplo: A divisão de um problema de tamanho n resulte em n subproblemas de tamanho n-1.
Uma solução utilizando Divisão e Conquista iria gastar um tempo absurdo (Exponencial).
n
Programação Dinâmica
É tipicamente aplicada a problemas de otimização. Geralmente há várias soluções possíveis.
Cada solução tem um valor, deve-se procurar a solução com o valor ótimo (mínimo ou máximo).
Descobrir uma rota entre Rio Verde e São Paulo
n soluções Solução 1 Solução 2 Solução 3 Solução 4
Programação Dinâmica
Projeto feito em 4 etapas:
1. Caracterizar a estrutura de uma solução
ótima.
“Definir como podemos encontrar a melhor solução para o problema, encontrar um esquema para isto.”
2. Definir recursivamente o valor de uma
solução ótima.
“Encontrar uma solução recursiva para o problema, pelo menos a sua equação de recorrência”
Programação Dinâmica
Projeto feito em 4 etapas:
3. Calcular o valor de uma solução ótima.
“Propor uma solução com Programação Dinâmica, baseada na solução recursiva, que seja capaz de encontrar o valor da melhor solução.”
4. Construir uma solução ótima a partir das
informações calculadas.
“Propor um algoritmo, que seja capaz de montar a solução ótima, baseado nos resultados do algoritmo de P.D.”
Programação Dinâmica
Exemplo: Programação de Linha de Montagem.
Fabrica com duas linhas de montagens.
C1 C2 X1 X2 a1,1 a1,2 a1,3 a1,4 a1,n a2,1 a,22 a2,3 a2,4 a2,n ... ... S1,1 S1,2 S1,3 S1,4 S1,n S2,1 S2,2 S2,3 S2,4 S2,n Saída Carros Entrada Chassis Linha 1 Linha 2
Programação Dinâmica
Um chassi de automóvel entra em cada linha de montagem, C1 e C2 são os custos para esta entrada.
As peças são adicionadas em uma série de estações (a), e um automóvel pronto sai no final, X1 e X2 é o custo de retirar o carro.
Cada linha possui n estações, numeradas com J=1,2,...,n Cada linha é enumerada i = (1,2).
Estação Si,j é a j_ésima estação da linha i.
A j_ésima estação da linha 1 executa a mesma coisa da j_ésima estação da linha 2.
Programação Dinâmica
O tempo de execução em cada linha pode váriar, mesmo naquelas que estejam na mesma posição nas duas linhas.
Problema: Utilizar as duas linhas para construir apenas um carro, do modo mais barato?
Otimizar o uso das linhas, selecionando as estações mais eficientes, aquelas que tenham um custo menor.
Programação Dinâmica
C1 C2 X1 X2 a1,1 a1,2 a1,3 a1,4 a1,n a2,1 a,22 a2,3 a2,4 a2,n ... ... S1,1 S1,2 S1,3 S1,4 S1,n S2,1 S2,2 S2,3 S2,4 S2,n Saída Carros Entrada Chassis Linha 1 Linha 2 t1,1 t2,1 t1,2 t2,2 t1,3 t2,3Programação Dinâmica
Consideramos ainda o tempo de entrada (C1 e
C2) e o tempo de Saída (X1 e X2).
Tempo de transferência de um chassi depois de passar pela estação Si,j é ti,j.
Programação Dinâmica
Definição:
Quais estações da linha 1 e quais estações da linha 2 serão utilizadas, de forma a minimizar o tempo total de passagem de um único carro.
Programação Dinâmica
Etapa 1. Caracterizar a estrutura de uma solução ótima.
A estrutura que permite definir o caminho mais rápido pela fabrica. Como encontrá-la.
A solução ótima para o problema da linha de montagem.
Qual é o menor custo até uma estação Si,j.
Si,j S2,j-1
S1,j-1 Sub1
Programação Dinâmica
O menor custo encontrado até a J_ésima estação é o menor custo entre o S1,j-1 e o S2,j-1, mais o
custo da estação Si,j.
Para encontrar a solução para um problema de uma determinada estação na estação j.
Resolver os subproblemas até a estação anterior j-1.
Programação Dinâmica
Etapa 2. Uma solução recursiva
Procurar uma solução adotando a abordagem Dividir & Conquistar.
Qual é o custo até Si,j. O menor dos custos
existente encontrado nas duas últimas estações, S1,j e S2,j.
Programação Dinâmica
Analisando o S1,j.
O menor custo é:
• Passando pela estação S1,j-1 e depois passar
diretamente para a estação S1,j.
ou
• Passando pela estação S2,j-1, ser transferido para a
linha 1, e depois passar pela estação S1,j.
Programação Dinâmica
F1[j] -> função para calcular o custo até a
j_ésima estação da linha 1.
C1 + a
1,1, se j=1
f1[j]= min(f1[j-1]+a
1,j;f2[j-1]+t
2,j-1+ a
1,j)
, se j>1
C2 + a
2,1, se j=1
f2[j]= min(f2[j-1]+a
2,j;f1[j-1]+t
1,j-1+ a
2,j)
, se j>1
Programação Dinâmica
Fi[j] é o tempo mais rápido possível para levar
um chassi até uma das linhas na estação j.
Permite calcular até as duas últimas estações.
S1,n e S2,n.
O custo total é dado por:
Programação Dinâmica
Perguntas?
Em cada execução do algoritmo, quantas serão as chamadas recursivas?
• a=2.
Quais serão o tamanho de cada subproblema?
• (n-1) para cada chamada.
Qual o caso onde nenhuma chamada é feita?
Programação Dinâmica
Etapa 3. Solução com Programação Dinâmica
Um algoritmo utilizando a técnica de programação dinâmica, consegue calcular o caminho mais rápido pela fabrica.
Tempo que ele demora é Θ(n), bem melhor que Θ(2n) de uma solução recursiva.
Podemos fazer muito melhor se calcularmos os valores fi[j], em uma ordem diferente do modo recursivo
Programação Dinâmica
Relembrando que, para j≥2, cada valor de
fi[j] depende apenas dos valores de f1[j-1] e f2[j-1].
Através desta proposta calculamos os valores de fi[j] na ordem de número de estações j crescente.
Algoritmo de PD.
Fastest_Way(a,t,e,x,n)
1. f[1][1] = e[1] + a[1,1];
2. f[2][1] = e[2] + a[2,1];
3. For (j=2;j<=n;j++) {
4. if(f[1][j-1] + a[1][j] <=f[2,j-1] + t[2,j-1] + a[1,j]) {
5. f[1][j] = f[1][j-1] + a[1][j]; 6. l[1][j] = 1; 7. } 8. else{ 9. f[1][j] = f[2][j-1] + t[2][j-1] + a[1][j]; 10. l[1][j] = 2; 11. }
Algoritmo de PD.
12. if(f[2][j-1] + a[2][j] <=f[1,j-1] + t[1,j-1] + a[2,j]) { 13. f[2][j] = f[2][j-1] + a[2][j]; 14. l[2][j] = 2; 15. } 16. else{ 17. f[2][j] = f[1][j-1] + t[1][j-1] + a[2][j]; 18. l[2][j] = 1; 19. } 20. } // fim for
Algoritmo de PD.
21. If (f[1][n] + x[1] <= f[2][n] + x[2]) { 22. f = f[1][n] + x[1]; 23. l = 1; 24. } 25. Else { 26. f = f[2][n] + x[2]; 27. l = 2; 28. }Programação Dinâmica
Funcionamento:
Entrada os valores vetores e, x, t e a, bem como n, que é o número de estações.
As duas primeiras linhas encontram os valores de f[1][1] e f[2][1]. e[1] e[2] a[1][1] a[2][1] = f[1][1] = f[2][1]
Programação Dinâmica
Funcionamento:
O vetor f[i][j] indicará o custo até chegar na posição sij.
O vetor l[i][j] indicará o caminho a ser percorrido até chegar na estação sij.
As linhas de 3 a 16 calculam os valores para f[i][j] e l[i][j].
Finalmente será calculado os valores para f e l.
• f conterá o custo do melhor caminho. • l apontará o melhor caminho.
Programação Dinâmica
e=[3,4] x=[3,4] t = 1 3 3 1 1 1 1 2 a = 10 2 5 9 3 8 4 6 3 4Programação Dinâmica
3 4 3 4 10 2 5 9 3 8 4 6 3 4 S1,1 S1,2 S1,3 S1,4 S1,5 S2,1 S2,2 S2,3 S2,4 S2,5 1 1 3 1 3 1 3 2Programação Dinâmica
J = 1 2 3 4 5 f = 13 15 20 29 32 12 16 22 25 29 1=13+2 2=12+1+2 1=15+5 2=16+1+5 1=20+9 2=22+1+9 1=29+3 2=25+2+3 2=12+4 1=13+4+1 2=16+6 1=15+6+3 2=22+3 1=20+3+3 2=25+4 1=29+4+1Programação Dinâmica
l = 1 1 1 2 2 2 2 2 f = 33 ou 33 l = 1 ou 2 l = 1 1 1 2 2 2 2 2Duas Soluções Ótimas:
Programação Dinâmica
Etapa 4.
Construir uma solução ótima
a partir das informações calculadas.
A construção de uma solução ótima, é feito pelo procedimento print-stations.
Ele imprime as estações usadas, em ordem decrescente de número de estações.
Programação Dinâmica
Print_station(l[][],l,n) 1. i=l;
2. Imprime “linha” + i + “, estação “ + n; 3. Para j = n até 2 faça
4. i = l[i][j];
5. imprime “linha” + i + “, estação “ + j-1
Resultado: linha 1, estação 5.
linha 2, estação 4. linha 2, estação 3.