Programação dinâmica é um método para construir algoritmos que resolvem problemas de otimização de forma eficiente, evitando recalcular subproblemas repetidos, ao invés de armazenar suas soluções previamente calculadas.
1. Wikipedia.org
Programação dinâmica é um método para a construção de algoritmos
para a resolução de problemas computacionais, em especial os de
optimização combinatória. Ela é aplicável a problemas no qual a solução
óptima pode ser computada a partir da solução óptima previamente
calculada e memorizada - de forma a evitar recalculo - de outros sub
problemas que, sobrepostos, compõem o problema original.
Exemplo (Fibonacci):
var m := map(0 → 1 1 → 1)
: 1,
function fib(n)
if map m does not contain key n
m[n] := fib(n − 1) + fib(n − 2)
return m[n]
Programação Dinâmica
2. Solução Sem Programação Dinâmica:
function fib(n)
if n = 0 or n = 1
return 1
else
return fib(n − 1) + fib(n − 2)
fib(5)
fib(4) + fib(3)
(fib(3) + fib(2)) + (fib(2) + fib(1))
((fib(2) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1))
(((fib(1) + fib(0)) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1))
Ou seja, existem inúmeras repetições nos cálculos necessários para
determinar o resultado final pretendido.
Programação Dinâmica
3. No entanto se usarmos o algoritmo anteriormente referido verificamos
que não necessitamos de calcular diversas vezes as mesmas parcelas,
basta construir a matriz e preenchê-la correctamente.
var m := map(0 → 1, 1 → 1)
function fib(n)
if map m does not contain key n
m[n] := fib(n − 1) + fib(n − 2)
return m[n]
[]
Fib(0)
b( ) Fib(1)
b( ) Fib(2)
b( ) Fib(3)
b( ) Fib(4)
b( ) Fib(5)
b( )
1 1 1+1=2 1+2=3 2+3=5 3+5=8
Programação Dinâmica
4. Cálculo de combinações sem repetição (coeficiente binomial):
n −1 n −1
C =C + Cr
n
r r −1
r
1 - - - -
n
1 1 - - -
1 1+1 = 2 1 - -
1 1+2 = 3 2+1 = 3 1 -
1 1+3 = 4 3+3 = 6 3+1 = 4 1
Programação Dinâmica
5. // binomial.c by: Steven Skiena
long binomial_coefficient(n,m) int n,m;
{
int i,j;
long bc[MAXN][MAXN];
for (i=0; i<=n; i++) bc[i][0] = 1;
f (j=0; j
for (j 0 j<=n; jj++) b [j][j] = 1
) bc[j][j] 1;
for (i=1; i<=n; i++)
for (j 1; j<i; j++)
(j=1;
bc[i][j] = bc[i-1][j-1] + bc[i-1][j];
return( bc[n][m] );
}
Programação Dinâmica
6. A programação dinâmica não serve apenas para satisfazer a
necessidade de termos diversas formas de resolver um problema. Trata-
se também de um método “muito” eficiente, ao nível da complexidade,
no entanto é preciso ter em atenção que ele acarreta um custo maior a
nível do uso de memória.
Este método é assim muito útil para a resolução de problemas de
optimização como o do caminho mais curto, Spanning trees mínimas,
etc. N entanto nem sempre é evidente reconhecermos quando e como
No id h d
podemos usar programação dinâmica.
Um dos truques é tentar verificar se existe um algoritmo recursivo para
recursivo,
a resolução do problema pretendido, que calcula diversas vezes os
mesmos sub problemas. A partir do momento que conseguimos
encontrar esse algoritmo temos a certeza de que o problema pode
alternativamente ser resolvido recorrendo à programação dinâmica.
Programação Dinâmica
7. A partir daqui só nos resta saber como implementar um algoritmo de
programação dinâmica. Como em tudo esta etapa requer
essencialmente treino e experiência no uso deste tipo de programação.
Inicialmente existem algumas dificuldades e tudo parece que acontece
por magia mas com o tempo rapidamente conseguimos chegar a
solução quase que intuitivas.
Enquanto isso não vai acontecendo aqui fica uma breve metodologia
para encontrar tais algoritmos mais f il
il i i facilmente:
1- Caracterizar a estrutura de uma solução óptima.
2-
2 Definir recursivamente o valor de uma solução óptima.
óptima
3- Calcular o valor de uma solução óptima ascendentemente
(Bottom-up).
4 Tentar construir a solução recorrendo à informação obtida
4- obtida.
Programação Dinâmica
11. Etapa 3: Cálculo do tempo optimal
f1[j] = min (f1[j-1] + a1,j, f2[j-1] + t2,j-1 + a1,j) for j > 1;
f2[j] = min (f2[j-1] + a2,j, f1[j-1] + t1,j-1 + a2,j) for j > 1;
f1[1] = e1 + a1,1;
f2[1] = e2 + a2,1.
function schedule(a[], t[], e[], x[], n)
1.
1 f1[1] ← e1 + a1,1;
1 11
2. f2[1] ← e2 + a2,1;
3. for j ← 2 to n do
4.
4 f1[j] ← min (f1[j 1] + a1 j f2[j 1] + t2 j 1 + a1 j);
(f1[j-1] a1,j, f2[j-1] t2,j-1 a1,j);
5. f2[j] ← min (f2[j-1] + a2,j, f1[j-1] + t1,j-1 + a2,j);
6. /* end for */
7 return( min( f1[n] + x1, f2[n] + x2 ));
x1
7.
Programação Dinâmica
12. Etapa 4: Construção do Caminho Óptimo
1. i ← l*;
2. print « linha » i « , posto » n;
3. for j ← n to 2 do
4. i ← mli[j];
5. print « linha » i « , posto » j-1;
6. /* end for */
Resultado:
linha 1, posto 6
linha 2 posto
2, 5
linha 2, posto 4
linha 1, posto 3
linha 2 posto 2
2,
linha 1, posto 1
Programação Dinâmica