IF672 - Algoritmos e Estruturas de Dados CIn - UFPE Programação Dinâmica Átila Valgueiro Malta...
-
Upload
rebeca-rios-domingos -
Category
Documents
-
view
310 -
download
0
Transcript of IF672 - Algoritmos e Estruturas de Dados CIn - UFPE Programação Dinâmica Átila Valgueiro Malta...
IF672 - Algoritmos e Estruturas de Dados CIn - UFPE
Programação Dinâmica
Átila Valgueiro Malta MoreiraJuliana Medeiros de LucenaRafael Alberto Gomes Pereira LimaRafael Loureiro de Carvalho
Sara Carvalho da Rocha BritoTiago Carneiro Pessoa CantoVictor Barbosa de Oliveira MedeirosVinícius Monteiro de Lira
MotivaçãoTécnicas de projeto de algoritmos
estudadas até agora:Algoritmos gulosos (greedy algorithms)
Kruskal , Dijkstra, ...Dividir para conquistar (divide and conquer)
Mergesort, Quicksort, ...
MotivaçãoUm mesmo problema resolvido
através 2 técnicas diferentesDiferentes performances
As técnicas anteriores não resolvem todos os problemas da maneira mais eficiente!!!
MotivaçãoPortanto...
Nenhuma lista de técnicas é exaustivaMas...
Em alguns problemas, não há técnica alguma que nos dê uma solução pelo menos aceitávelProblemas intratáveis (NP-completos)
Estrutura de um problema de Programação DinâmicaGeralmente possuem estruturas recursivas
Subproblemas devem ser resolvidos para que a solução final possa ser alcançada
Em geral aplicados a problemas de otimizaçãoBuscam uma solução ótima
Por que não recursão?Se a estrutura do problema é recursiva,
por que um algoritmo recursivo não seria uma boa solução?Subproblemas não são
independentes.Algoritmos puramente recursivos trabalharão mais que o necessário resolvendo os subsubproblemas comuns mais de uma vez.
Por que não recursão?Uma boa estratégia seria ter uma
tabela onde:Pudéssemos guardar os resultados de sub-instâncias do problema que já foram resolvidas.
E onde consultas poderiam ser feitas sob demanda.
Um exemplo simples: FibonacciOs números de Fibonacci são definidos
pela função:
Definidos em termos de uma função recursivaSeria natural imaginar que a solução
algorítmica correspondente fosse as mais apropriada
F(0) = 1, n = 0 F(1) = 1, n = 1F(n) = F(n-1) + F(n-2), n > 1
Um exemplo simples: FibonacciCódigo recursivo para os números de
Fibonacci:int fibonacci(int n){ if(n <= 1){ return 1; } else{ return fibonacci(n - 1) + fibonacci(n - 2); }}
Um exemplo simples: FibonacciNo entanto...
O algoritmo apresentado é ineficiente pois há trabalho redundante:
Um exemplo simples: FibonacciOs cálculos redundantes levam o
algoritmo a ter desempenho exponencial Um algoritmo mais “experto” poderia
ser feito com programação dinâmicaGuardaria apenas os dois últimos resultados
Um exemplo simples: Fibonacci int fibonacci(int n){ int resultado = 1; if(n > 1){ int ultimo = 1; int penultimo = 1; for(int i = 2; i <= n; i++){ resultado = ultimo + penultimo; penultimo = ultimo; ultimo = resultado; } } return resultado; }
Knapsack(Problema da Mochila)
Knapsack(Problema da Mochila)Busca calcular a melhor maneira de se
armazenar em um compartimento qualquer, muitos itens com valores agregados, de forma que o somatório dos valores de tais itens seja o máximo possível dentre as possibilidades de combinação de itens.
Esse problema tem importantes aplicações, como por exemplo o carregamento ótimo de containers.
Importante para supermercados e empresas de armazenagem e logística em geral.
Knapsack – Como Funciona?Vamos criar uma matriz chamada
maxTab, de ordem (N+1) x (C+1), onde:N = número de itens;C = Capacidade da mochila.
As linhas representam cada item.As colunas a capacidade máxima da
mochila.
Knapsack – Como Funciona?A idéia do algoritmo é começar com uma
mochila de capacidade 1 e descobrir o valor máximo possível para esta mochila. Depois se passa para uma mochila de capacidade 2, que aproveitando as informações da mochila de capacidade atual -1 (nesse caso, 1) descobre o valor máximo para uma mochila de capacidade 2. Isso será feito até capacidade atual ser igual à C. Além da capacidade ir crescendo, também vai se adicionando novos itens no processo.
Knapsack – Como Funciona?A idéia é ir percorrendo por linha (ou seja, por
item) tal tabela, e para a coluna j atual, que representa capacidade atual, analisar se o item atual i (linha atual) cabe na mochila de capacidade j. Se couber é preciso escolher o maior valor entre: valor na mochila de mesma capacidade j que não
tinha esse item (essa informação estará em maxTab[i-1][j]).
Soma do valor do item com o valor na mochila de capacidade (j – peso do item i) e que não tinha esse item(maxTab[i-1][j – peso do item i]).
Knapsack – Como Funciona?Então, se couber (itens[i].peso <= j), teremos: maxTab[i][j] = Máximo(maxTab[i-1][j], valor do item + maxTab[i-1][j – peso do item i]);
Se não couber, significa que o maior valor para essa mochila será o valor da mochila de mesma capacidade, mas que não tem esse item:maxTab[i][j] = maxTab[i-1][j];
Knapsack – ExemploCapacidade da mochila = 5 kgItens:
1. Peso = 4, Frete = 22. Peso = 2, Frete = 13. Peso = 1, Frete = 34. Peso = 2, Frete = 4
Knapsack – Exemplo
0 0 0 0 0 00 ? ? ? ? ?0 ? ? ? ? ?0 ? ? ? ? ?0 ? ? ? ? ?
4 2 1 22 1 3 4
Peso
Frete
Itens
maxTab[i][j] = maxTab[i-1][j];
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens
maxTab[i][j] = maxTab[i-1][j];
0 0 0 0 0 00 0 ? ? ? ?0 ? ? ? ? ?0 ? ? ? ? ?0 ? ? ? ? ?
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens
maxTab[i][j] = maxTab[i-1][j];
0 0 0 0 0 00 0 0 ? ? ?0 ? ? ? ? ?0 ? ? ? ? ?0 ? ? ? ? ?
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens0 0 0 0 0 00 0 0 0 ? ?0 ? ? ? ? ?0 ? ? ? ? ?0 ? ? ? ? ?
maxTab[i][j] = MAX (maxTab[i-1][j], itens[i].frete + maxTab[i-1][j - itens[i].peso])
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens0 0 0 0 0 00 0 0 0 2 ?0 ? ? ? ? ?0 ? ? ? ? ?0 ? ? ? ? ?
maxTab[i][j] = MAX (maxTab[i-1][j], itens[i].frete + maxTab[i-1][j - itens[i].peso])
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens
maxTab[i][j] = maxTab[i-1][j];
0 0 0 0 0 00 0 0 0 2 20 ? ? ? ? ?0 ? ? ? ? ?0 ? ? ? ? ?
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens0 0 0 0 0 00 0 0 0 2 20 0 ? ? ? ?0 ? ? ? ? ?0 ? ? ? ? ?
maxTab[i][j] = MAX (maxTab[i-1][j], itens[i].frete + maxTab[i-1][j - itens[i].peso])
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens0 0 0 0 0 00 0 0 0 2 20 0 1 ? ? ?0 ? ? ? ? ?0 ? ? ? ? ?
maxTab[i][j] = MAX (maxTab[i-1][j], itens[i].frete + maxTab[i-1][j - itens[i].peso])
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens0 0 0 0 0 00 0 0 0 2 20 0 1 1 ? ?0 ? ? ? ? ?0 ? ? ? ? ?
maxTab[i][j] = MAX (maxTab[i-1][j], itens[i].frete + maxTab[i-1][j - itens[i].peso])
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens0 0 0 0 0 00 0 0 0 2 20 0 1 1 2 ?0 ? ? ? ? ?0 ? ? ? ? ?
maxTab[i][j] = MAX (maxTab[i-1][j], itens[i].frete + maxTab[i-1][j - itens[i].peso])
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens0 0 0 0 0 00 0 0 0 2 20 0 1 1 2 20 ? ? ? ? ?0 ? ? ? ? ?
maxTab[i][j] = MAX (maxTab[i-1][j], itens[i].frete + maxTab[i-1][j - itens[i].peso])
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens0 0 0 0 0 00 0 0 0 2 20 0 1 1 2 20 3 ? ? ? ?0 ? ? ? ? ?
maxTab[i][j] = MAX (maxTab[i-1][j], itens[i].frete + maxTab[i-1][j - itens[i].peso])
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens0 0 0 0 0 00 0 0 0 2 20 0 1 1 2 20 3 3 ? ? ?0 ? ? ? ? ?
maxTab[i][j] = MAX (maxTab[i-1][j], itens[i].frete + maxTab[i-1][j - itens[i].peso])
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens0 0 0 0 0 00 0 0 0 2 20 0 1 1 2 20 3 3 4 ? ?0 ? ? ? ? ?
maxTab[i][j] = MAX (maxTab[i-1][j], itens[i].frete + maxTab[i-1][j - itens[i].peso])
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens0 0 0 0 0 00 0 0 0 2 20 0 1 1 2 20 3 3 4 4 ?0 ? ? ? ? ?
maxTab[i][j] = MAX (maxTab[i-1][j], itens[i].frete + maxTab[i-1][j - itens[i].peso])
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens0 0 0 0 0 00 0 0 0 2 20 0 1 1 2 20 3 3 4 4 50 ? ? ? ? ? maxTab[i][j] = maxTab[i-1][j];
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens0 0 0 0 0 00 0 0 0 2 20 0 1 1 2 20 3 3 4 4 50 3 ? ? ? ?
maxTab[i][j] = MAX (maxTab[i-1][j], itens[i].frete + maxTab[i-1][j - itens[i].peso])
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens0 0 0 0 0 00 0 0 0 2 20 0 1 1 2 20 3 3 4 4 50 3 4 ? ? ?
maxTab[i][j] = MAX (maxTab[i-1][j], itens[i].frete + maxTab[i-1][j - itens[i].peso])
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens0 0 0 0 0 00 0 0 0 2 20 0 1 1 2 20 3 3 4 4 50 3 4 7 ? ?
maxTab[i][j] = MAX (maxTab[i-1][j], itens[i].frete + maxTab[i-1][j - itens[i].peso])
Knapsack – Exemplo
4 2 1 22 1 3 4
Peso
Frete
Itens0 0 0 0 0 00 0 0 0 2 20 0 1 1 2 20 3 3 4 4 50 3 4 7 7 ?
maxTab[i][j] = MAX (maxTab[i-1][j], itens[i].frete + maxTab[i-1][j - itens[i].peso])
Knapsack – Exemplo0 0 0 0 0 00 0 0 0 2 20 0 1 1 2 20 3 3 4 4 50 3 4 7 7 8
O 8 representa o valor do maior frete possível que se pode carregar nesta mochila de capacidade 5.
Knapsack – Outra Implementação
Knapsack – Recuperando Informações.Observe que neste algoritmo não obtemos o
subconjunto de itens correspondentes que foram inseridos na mochila.
Se desejássemos obter o subconjunto correspondente, então usaríamos uma flag em cada item para recuperar esta informação.
Knapsack – ComplexidadeExistem (nC) entradas na tabela (onde, n é
o número de itens e C a capacidade da mochila), cada uma é computada em tempo constante a partir de uma ou duas outras entradas.
Logo, a complexidade é O(nC).Obs: Knaspack não é um algoritmo
polinomial pois k (capacidade da mochila) pode ser um valor infinitamente grande.
String MatchingEste algoritmo resume-se em uma
busca de padrões dentro de um conjunto de informações.
São muitas as variações deste problema, desde procurar determinadas palavras ou sentenças em um texto até procurar um determinado objeto dentro de uma seqüência de bits que representam uma imagem.
Algoritmo inocente ou força brutaPode se resolver o problema do String
Matching através da força bruta.Não é inteligente o bastante para
aproveitar os mismatchs, quando acha um caractere em P que não pode ser casado em T.
É deslocada uma posição de cada vez, independente de ter match ou não.
Complexidade: O(n2) .
Força Bruta - Exemplo
Algoritmo De Boyer-MooreConsiste em um algoritmo mais eficiente
na resolução do problema de string matching.
A cada mismatch um novo incremento é calculado para saber qual será a próxima posição do texto que será comparada.
Possui duas versões para este calculoAs comparações entre os caracteres do
texto e do padrão é sempre feito da direita para a esquerda
Boyer-Moore (1ª versão)De inicio, deve-se criar uma tabela com a posição
da última ocorrências de cada caractere do padrão.
A cada mismatch um novo incremento deverá ser calculado da seguinte forma:Pega-se o caractere do texto que esta na
posição: deslocamento + 1.Desloca-se o suficiente para alinhar a ultima
ocorrência desse caractere do padrão com o caractere correspondente no texto.
Boyer-Moore (1ª versão)Texto: addcccadcbaPadrão: ddc
Criando Tabela De Ocorrência do padrão:
Boyer-Moore (1ª versão)addcccadcba
ddcMismatch (pega-se o caractere da posição 5 (‘c’) do texto e procura a sua ultima ocorrência no padrão)
Boyer-Moore (1ª versão)-Exemplo
addcccadcba
ddcMatch (Encontrou uma ocorrência na posição 1 do texto, continua a procura por novas ocorrências)
Boyer-Moore (1ª versão)-Exemplo
addcccadcba
ddcMismatch (pega-se o caractere da posição 5 (‘c’) do texto e procura a sua ultima ocorrência no padrão)
Boyer-Moore (1ª versão)-Exemplo
addcccadcba
ddcMismatch (pega-se o caractere da posição 7 (‘a’) do texto e procura a sua ultima ocorrência no padrão)
Boyer-Moore (1ª versão)-Exemplo
addcccadcba
ddcMismatch (pega-se o caractere da posição 10 (‘a’) do texto e procura a sua ultima ocorrência no padrão)
Boyer-Moore (1ª versão)-Exemplo
addcccadcba
ddcO tamanho do deslocamento + o
comprimento do padrão é maior que o tamanho do texto. (termina o algoritmo).
Boyer-Moore (2ª versão)Tentar casar o padrão com o pedaço
do texto anteriormente casado.
Exemplo:Texto: aabcaccacbacPadrão: cacbac
Boyer-Moore (2ª versão)1 2 3 4 5 6 7 8 9 0 1 2c a c b a ca a b c a c c a c b a c c a c b a c c a c b a c No primeiro caso, o padrão deve ser
deslocado para a direita até casar com o pedaço do texto anteriormente casado, no caso ac, deslocando o padrão 3 posições à direita.
O processo é repetido mais uma vez e o casamento entre P e T ocorre.
Algoritmo De Boyer-Moore (versão 3)Esta versão do algoritmo de Boyer-Moore
consiste em utilizar as duas heurísticas de forma independente e paralela.
Quando ocorre uma falha no casamento, cada uma das heurísiticas propõe um valor para o novo deslocamento válido. O algoritmo de Boyer e Moore escolhe o maior valor.
BibliografiaWeiss, Mark Allen. Data Structures &
Algorithm Analysis in Java, Addison Wesley-Longman
Cormen et al. Algoritmos: Teoria e Prática, Editora Campos
Manber, Udi. Introduction to Algorithms: A Creative Approach, Addison-Wesley
www.ime.usp.br/~mms/macl222s2006/aula18%20Algoritmos%20de%10Busca%20de%20Palavras%20em%20Texto.doc.
IF672 - Algoritmos e Estruturas de Dados CIn - UFPE
Programação Dinâmica
Átila Valgueiro Malta MoreiraJuliana Medeiros de LucenaRafael Alberto Gomes Pereira
LimaRafael Loureiro de Carvalho
Sara Carvalho da Rocha BritoTiago Carneiro Pessoa CantoVictor Barbosa de Oliveira MedeirosVinícius Monteiro de Lira