Você está na página 1de 64

Complexidade de Algoritmos

Programação Dinâmica

Ricardo Ferreira de Oliveira


Professor
Roteiro
Neste tópico iremos ver:

• Definição.
• Requisitos
• A idéia geral da técnica
• Exemplo 1: Série de Fibonacci
• Exemplo 2: Problema da Pirâmide
• Exemplo 3: Problema da Mochila

Complexidade de Algoritmos> Conceitos Básicos


Definição
Programação dinâmica é um método para a construção de algoritmos para a
resolução de problemas computacionais, em especial os de otimização
combinatória . Ela é aplicável a problemas nos quais a solução ótima pode
<1>

ser computada a partir da solução ótima previamente calculada e


memorizada - de forma a evitar recálculo - de outros subproblemas que,
sobrepostos, compõem o problema original.

<1> A Otimização Combinatória é um ramo da ciência da computação e da matemática aplicada que estuda problemas de otimização em
conjuntos finitos.

Complexidade de Algoritmos> Conceitos Básicos


Requisitos
O que um problema de otimização deve ter para que a programação dinâmica
seja aplicável são duas principais características?

Resposta: subestrutura ótima e superposição de subproblemas.

• Um problema apresenta uma subestrutura ótima quando uma solução ótima


para o problema contém em seu interior soluções ótimas para subproblemas.

• A superposição de subproblemas acontece quando um algoritmo recursivo


reexamina o mesmo problema muitas vezes.

Complexidade de Algoritmos> Conceitos Básicos


A Idéia Geral da Técnica
A idéia por trás de programação dinâmica é bastante simples. Em geral, para resolver um
problema determinado, é necessário resolver as diferentes partes do problema
(subproblemas), depois combinar as soluções dos subproblemas para alcançar uma
solução completa. Frequentemente, muitos destes subproblemas são a mesma coisa.

A abordagem da programação dinâmica procura resolver cada subproblema apenas uma


vez, o que reduz o número de cálculos: uma vez que a solução de um subproblema
dado tenha sido calculada, ela é armazenado ou "memorizada": a próxima vez que a
mesma solução for necessária, ela é simplesmente pesquisada de forma bottom up.
Esta abordagem é especialmente útil quando o número de repetições de
subproblemas cresce exponencialmente em função do tamanho da entrada.
.

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 1: Série de Fibonacci
Como exemplo simples de programação dinâmica, com alguma frequência,
alguns textos, utilizam a determinação da Sequência de Fibonacci, quando
implementada de forma recursiva. Isso porque quando a forma recursiva é
implementada sem maiores cuidados, sem memorização, o seu cálculo de
tempo cresce exponencialmente.
Observe que a rigor esse caso não é um problema de programação dinâmica,
visto que o cálculo do n-ésimo número de Fibonacci cresce linearmente, e
não exponencialmente. Porém este exemplo ainda assim é utilizado, pois a
simplicidade é grande.

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 1: Série de Fibonacci

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 1: Série de Fibonacci
A Sequência de Fibonacci consiste de uma sequência de inteiros, tal que:
F(0) = 0;
F(1) = 1;
F(n) = F(n-1) + F(n-2) , se n > 1

n: 0 1 2 3 4 5 6 7 8 9 10
F(n): 0 1 1 2 3 5 8 13 21 34 55

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 1: Série de Fibonacci
Solução óbvia:

if n ≤ 1
então F(n) = n
senão F(n) = F(n – 1) + F(n – 2)

Número de chamadas recursivas para calcular F(5)?

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 1: Série de Fibonacci

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 1: Série de Fibonacci

fib(2) é chamada 3
vezes!

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 1: Série de Fibonacci
F(7) • • • F(10) é chamada 1 vez
F(8) F(9) é chamada 1 vez
F(6) • • • F(8) é chamada 2 vezes
F(9) F(7) é chamada 3 vezes
F(6) • • • F(6) é chamada 5 vezes
F(7) F(5) é chamada 8 vezes
F(5) • • • F(4) é chamada 13 vezes
F(10) F(3) é chamada 21 vezes
F(6) • • • F(2) é chamada 34 vezes
F(7) F(1) é chamada 55 vezes
F(5) • • •
F(8)
F(5) • • •
F(6) A lista de chamadas consiste
também de uma série de Fibonacci
F(4) • • •

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 1: Série de Fibonacci
Solução otimizada:
• Calcular cada subproblema uma vez
• Armazenar o resultado
• Buscar a informação toda vez que o subproblema for considerado.

Armazenamento: Usar um vetor de tamanho n+1, e calcular os valores a


partir de I = 0. Calcular cada subproblema uma vez

Custo desta Solução?

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 1: Série de Fibonacci

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 2: Problema da Pirâmide

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 2: Problema da Pirâmide

Limites: todos os números da pirâmide são inteiros


entre 0 e 99 e o número de linhas do triângulo é no
máximo 100.

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 2: Problema da Pirâmide

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 2: Problema da Pirâmide

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 2: Problema da Pirâmide

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 2: Problema da Pirâmide

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 2: Problema da Pirâmide

Para o exemplo, a
solucao é 7 mais o
maximo
entre o valor da
melhor rota de cada
uma das
subpiramides

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 2: Problema da Pirâmide

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 2: Problema da Pirâmide

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 2: Problema da Pirâmide

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 2: Problema da Pirâmide

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 2: Problema da Pirâmide

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 2: Problema da Pirâmide

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 2: Problema da Pirâmide

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 2: Problema da Pirâmide

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 2: Problema da Pirâmide

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 2: Problema da Pirâmide

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 3: Problema da Mochila

O problema da mochila (em inglês, Knapsack


problem) é um problema de optimização
combinatória. O nome dá-se devido ao modelo
de uma situação em que é necessário preencher
uma mochila com objetos de diferentes pesos e
valores. O objetivo é que se preencha a
mochila com o maior valor possível, não
ultrapassando o peso máximo.

Este problema é a base do primeiro algoritmo de


chave pública (chaves assimétricas).

Complexidade de Algoritmos> Conceitos Básicos


Exemplo 3: Problema da Mochila
Por ser um problema combinatório é possível resolve-lo por enumeração
exaustiva, ou seja tentar todas as soluções possíveis e comparando-as para
identificar a melhor solução. Porém isso se torna completamente inviável
uma vez que, mesmo em pequenas dimensões como um problema com
apenas 20 itens, haveria um número enorme de respostas. Em um
problema com mais de 80 itens, o algoritmo levaria bilhões de anos para
ser concluido. Assim, o método de resolução por enumeração exaustiva é
de utilidade muito reduzida, senão mesmo nula, para problemas de grande
dimensão.

Complexidade de Algoritmos> Conceitos Básicos


Solução do Problema da Mochila com
Programação Dinâmica
Esta foi a primeira técnica mais inteligente que foi usada para resolver esse
problema, na década de 50. É um método aprimorado de usar
recursividade que ao invés de chamar uma função várias vezes ele, na
primeira vez que é chamado, armazena o resultado para que cada vez que a
função for chamada novamente volte o resultado e não uma requisição
para ser resolvida.

Outras técnicas encontram-se em:

http://pt.wikipedia.org/wiki/Problema_da_mochila

Complexidade de Algoritmos> Conceitos Básicos


Solução do Problema da Mochila com
Programação Dinâmica
Entrada: Valores (armazenados no vetor v)
Pesos (armazenados no vetor w)
Número de itens distintos (n)
Capacidade da mochila (W)

for w from 0 to W do
m[0, w] := 0
end for
for i from 1 to n do
for j from 0 to W do
if j >= w[i] then
m[i, j] := max(m[i-1, j], m[i-1, j-w[i]] + v[i])
else
m[i, j] := m[i-1, j]
end if
end for
end for

Complexidade de Algoritmos> Conceitos Básicos


Implementação do Problema da Mochila em Java
public class Mochila {
public static void main(String[] args) {
int [] w = {3, 4, 5, 6, 8, 9, 10 }; // Pesos
int [] v = {10, 2, 15, 5, 8, 3, 7 }; // Valores
int W = 20;// Peso máximo na bolsa
int n = v.length; // Número de itens

int [][] m = new int[n+1][W+1];


for ( int cw=0; cw<=W; cw++ ) {
m[0][cw] = 0;
}
for ( int i=1; i<=n; i++ ) {
for ( int j=0; j<=W; j++ ) {
if ( j >= w[i-1] ) {
m[i][j] = maximo(m[i-1][j], m[i-1][j-w[i-1]] + v[i-1]);
} else {
m[i][j] = m[i-1][j];
}
}
}

for ( int i=1; i<=n; i++ ) { for ( int j=0; j<=W; j++ ) { System.out.print( " " + m[i][j] ); } System.out.println(); } }

public static int maximo( int a, int b ) { if ( a > b ) { return a; } else { return b; } } }

Complexidade de Algoritmos> Conceitos Básicos


w = {2, 3, 4, 5 };
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

4
w = {2, 3, 4, 5 };
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

4
J>=w[i-1]?
w = {2, 3, 4, 5 };
0>=2? Não!
m[1][0] = m[0][0];
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0

4
J>=w[i-1]?
w = {2, 3, 4, 5 };
1>=2? Não!
m[1][1] = m[0][1];
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0

4
J>=w[i-1]?
w = {2, 3, 4, 5 };
2>=2? Sim!
m[1][2] = máx (m[0][2] e m[0][2-2]+v[0])
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4

4
J>=w[i-1]?
w = {2, 3, 4, 5 };
2>=2? Sim!
m[1][2] = máx (m[0][2] e m[0][2-2]+v[0])
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4

4
J>=w[i-1]?
w = {2, 3, 4, 5 };
3>=2? Sim!
m[1][3] = máx (m[0][3] e m[0][3-2]+v[0])
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4

4
J>=w[i-1]?
w = {2, 3, 4, 5 };
4>=2? Sim!
m[1][4] = máx (m[0][4] e m[0][4-2]+v[0])
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4

4
w = {2, 3, 4, 5 };
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

4
J>=w[i-1]?
w = {2, 3, 4, 5 };
0>=3? Não!
M[2][0] = m[1][0];
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

2 0

4
J>=w[i-1]?
w = {2, 3, 4, 5 };
1>=3? Não!
M[2][1] = m[1][1];
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

2 0 0

4
J>=w[i-1]? w = {2, 3, 4, 5 };
2>=3? Não! v = {4, 7, 6, 8 };
M[2][2] = m[1][2];

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

2 0 0 4

4
J>=w[i-1]?
w = {2, 3, 4, 5 };
3>=3? Sim!
m[2][3] = máx (m[1][3] e m[1][3-3]+v[1])
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

2 0 0 4 7

4
J>=w[i-1]?
w = {2, 3, 4, 5 };
4>=3? Sim!
m[2][4] = máx (m[1][4] e m[1][4-3]+v[1])
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

2 0 0 4 7 7

4
J>=w[i-1]?
w = {2, 3, 4, 5 };
5>=3? Sim!
m[2][5] = máx (m[1][5] e m[1][5-3]+v[1])
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4
Comparou
m[1][5] = 4
2 0 0 4 7 7 11 Com
m[1][2]+v[1] = 4+7
Ganhou 4+7=11
3

4
w = {2, 3, 4, 5 };
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

2 0 0 4 7 7 11 11 11 11 11

4
J>=w[i-1]? w = {2, 3, 4, 5 };
0>=4? Não! v = {4, 7, 6, 8 };
m[3][0] = m[2][0];

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

2 0 0 4 7 7 11 11 11 11 11

3 0

4
J>=w[i-1]?
w = {2, 3, 4, 5 };
4>=4? Sim!
M[3][4] = máx (m[2][4] e m[2][4-4]+v[2])
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

2 0 0 4 7 7 11 11 11 11 11
Comparou
m[2][4] = 7
3 0 0 4 7 7 com
m[2][0]+v[2] = 0+6
Ganhou 7
4
J>=w[i-1]?
w = {2, 3, 4, 5 };
5>=4? Sim!
M[3][5] = máx (m[2][5] e m[2][5-4]+v[2])
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

2 0 0 4 7 7 11 11 11 11 11

3 0 0 4 7 7 11

4
J>=w[i-1]?
w = {2, 3, 4, 5 };
7>=4? Sim!
M[3][7] = máx (m[2][7] e m[2][7-4]+v[2])
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

2 0 0 4 7 7 11 11 11 11 11

3 0 0 4 7 7 11 11 13

4
J>=w[i-1]?
w = {2, 3, 4, 5 };
8>=4? Sim!
M[3][8] = máx (m[2][8] e m[2][8-4]+v[2])
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

2 0 0 4 7 7 11 11 11 11 11

3 0 0 4 7 7 11 11 13 13

4
J>=w[i-1]?
w = {2, 3, 4, 5 };
9>=4? Sim!
M[3][9] = máx (m[2][9] e m[2][9-4]+v[2])
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

2 0 0 4 7 7 11 11 11 11 11

3 0 0 4 7 7 11 11 13 13 17

4
J>=w[i-1]?
w = {2, 3, 4, 5 };
0>=5? Não!
M[4][0] = m[3][0];
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

2 0 0 4 7 7 11 11 11 11 11

3 0 0 4 7 7 11 11 13 13 17

4 0
w = {2, 3, 4, 5 };
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

2 0 0 4 7 7 11 11 11 11 11

3 0 0 4 7 7 11 11 13 13 17

4 0 0 4 7 7
J>=w[i-1]?
w = {2, 3, 4, 5 };
5>=5? Sim!
M[4][5] = máx (m[3][5] e m[3][5-5]+v[3])
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

2 0 0 4 7 7 11 11 11 11 11

3 0 0 4 7 7 11 11 13 13 17

4 0 0 4 7 7 11
w = {2, 3, 4, 5 };
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

2 0 0 4 7 7 11 11 11 11 11

3 0 0 4 7 7 11 11 13 13 17

4 0 0 4 7 7 11 11 13 15 17
w = {2, 3, 4, 5 };
v = {4, 7, 6, 8 };

0 1 2 3 4 5 6 7 8 9

0 0 0 0 0 0 0 0 0 0 0

1 0 0 4 4 4 4 4 4 4 4

2 0 0 4 7 7 11 11 11 11 11

3 0 0 4 7 7 11 11 13 13 17

4 0 0 4 7 7 11 11 13 15 17
Solução do Problema da Mochila com
Programação Dinâmica
Selecionados então os objetos:

1, 2 e 3

Complexidade de Algoritmos> Conceitos Básicos

Você também pode gostar