O que é programação dinâmica ?
Como é diferente de recursão, memorização, etc?
algorithm
dynamic-programming
smac89
fonte
fonte
Respostas:
A programação dinâmica é quando você usa o conhecimento passado para facilitar a solução de um problema futuro.
Um bom exemplo é resolver a sequência de Fibonacci para n = 1.000.002.
Este será um processo muito longo, mas e se eu lhe der os resultados para n = 1.000.000 en = 1.000.001? De repente, o problema tornou-se mais gerenciável.
A programação dinâmica é muito usada em problemas de cadeia, como o problema de edição de cadeia. Você resolve um subconjunto (s) do problema e, em seguida, usa essas informações para resolver o problema original mais difícil.
Com a programação dinâmica, você armazena seus resultados em algum tipo de tabela em geral. Quando você precisar da resposta para um problema, consulte a tabela e veja se você já sabe o que é. Caso contrário, use os dados da sua tabela para dar a si mesmo um trampolim em direção à resposta.
O livro Algorithms de Cormen tem um ótimo capítulo sobre programação dinâmica. E é grátis no Google Livros! Confira aqui.
fonte
A programação dinâmica é uma técnica usada para evitar computar várias vezes o mesmo subproblema em um algoritmo recursivo.
Vamos pegar o exemplo simples dos números de Fibonacci: encontrar o enésimo número de Fibonacci definido por
F n = F n-1 + F n-2 e F 0 = 0, F 1 = 1
Recursão
A maneira óbvia de fazer isso é recursiva:
Programaçao dinamica
A recursão faz muitos cálculos desnecessários porque um determinado número de Fibonacci será calculado várias vezes. Uma maneira fácil de melhorar isso é armazenar em cache os resultados:
Uma maneira melhor de fazer isso é se livrar da recursão, avaliando os resultados na ordem correta:
Podemos até usar espaço constante e armazenar apenas os resultados parciais necessários ao longo do caminho:
Como aplicar a programação dinâmica?
A programação dinâmica geralmente trabalha para problemas que têm uma ordem inerente da esquerda para a direita, como seqüências de caracteres, árvores ou seqüências inteiras. Se o algoritmo recursivo ingênuo não computar o mesmo subproblema várias vezes, a programação dinâmica não ajudará.
Fiz uma coleção de problemas para ajudar a entender a lógica: https://github.com/tristanguigue/dynamic-programing
fonte
if n in cache
como no exemplo de cima para baixo ou estou perdendo alguma coisa.Memoização é quando você armazena resultados anteriores de uma chamada de função (uma função real sempre retorna a mesma coisa, considerando as mesmas entradas). Não faz diferença para a complexidade algorítmica antes que os resultados sejam armazenados.
Recursão é o método de uma função que se chama, geralmente com um conjunto de dados menor. Como a maioria das funções recursivas pode ser convertida em funções iterativas semelhantes, isso também não faz diferença para a complexidade algorítmica.
A programação dinâmica é o processo de resolver sub-problemas mais fáceis de resolver e criar a resposta a partir disso. A maioria dos algoritmos de DP estará nos tempos de execução entre um algoritmo Greedy (se houver) e um algoritmo exponencial (enumere todas as possibilidades e encontre a melhor).
fonte
É uma otimização do seu algoritmo que reduz o tempo de execução.
Enquanto um algoritmo ganancioso é geralmente chamado ingênuo , porque pode ser executado várias vezes no mesmo conjunto de dados, a Programação Dinâmica evita essa armadilha por meio de um entendimento mais profundo dos resultados parciais que devem ser armazenados para ajudar a construir a solução final.
Um exemplo simples é percorrer uma árvore ou um gráfico apenas através dos nós que contribuiriam com a solução ou colocar em uma tabela as soluções que você encontrou até agora para evitar percorrer os mesmos nós repetidamente.
Aqui está um exemplo de um problema adequado para programação dinâmica, do juiz on-line da UVA: Edit Steps Ladder.
Vou fazer um resumo rápido da parte importante da análise desse problema, extraída do livro Desafios de Programação, sugiro que você verifique.
Aqui, uma análise muito particular do que é necessário para obter os melhores resultados parciais é o que torna a solução "dinâmica".
Aqui está uma solução alternativa completa para o mesmo problema. Também é "dinâmico", embora sua execução seja diferente. Sugiro que você verifique a eficiência da solução enviando-a ao juiz on-line da UVA. Acho incrível como um problema tão pesado foi tratado com tanta eficiência.
fonte
Os principais bits da programação dinâmica são "subproblemas sobrepostos" e "subestrutura ideal". Essas propriedades de um problema significam que uma solução ótima é composta pelas soluções ótimas para seus subproblemas. Por exemplo, os problemas de caminho mais curto exibem a subestrutura ideal. O caminho mais curto de A a C é o caminho mais curto de A para algum nó B, seguido pelo caminho mais curto desse nó B para C.
Mais detalhadamente, para resolver um problema de caminho mais curto, você irá:
Como estamos trabalhando de baixo para cima, já temos soluções para os subproblemas na hora de usá-los, memorizando-os.
Lembre-se de que problemas de programação dinâmica devem ter subproblemas sobrepostos e subestrutura ideal. Gerar a sequência de Fibonacci não é um problema de programação dinâmica; utiliza memoização porque possui subproblemas sobrepostos, mas não possui subestrutura ideal (porque não há nenhum problema de otimização envolvido).
fonte
Programaçao dinamica
Definição
A programação dinâmica (DP) é uma técnica geral de design de algoritmo para resolver problemas com subproblemas sobrepostos. Esta técnica foi inventada pelo matemático americano "Richard Bellman" na década de 1950.
Ideia-chave
A idéia principal é salvar respostas de subproblemas menores sobrepostos para evitar a recomputação.
Propriedades de programação dinâmica
fonte
Eu também sou muito novo na Programação Dinâmica (um algoritmo poderoso para tipos específicos de problemas)
Em palavras mais simples, pense na programação dinâmica como uma abordagem recursiva ao usar o conhecimento anterior
Conhecimento prévio é o que mais importa aqui. Acompanhe a solução dos sub-problemas que você já possui.
Considere isso, exemplo mais básico para dp da Wikipedia
Encontrando a sequência de fibonacci
Vamos quebrar a chamada de função com digamos n = 5
Em particular, a fib (2) foi calculada três vezes a partir do zero. Em exemplos maiores, muitos outros valores de fib, ou subproblemas, são recalculados, levando a um algoritmo de tempo exponencial.
Agora, vamos tentar armazenando o valor que já descobrimos em uma estrutura de dados, como um Mapa
Aqui estamos salvando a solução de subproblemas no mapa, se ainda não a tivermos. Essa técnica de salvar valores que já calculamos é denominada Memoização.
Por fim, para um problema, primeiro tente encontrar os estados (possíveis subproblemas e tente pensar na melhor abordagem de recursão para poder usar a solução do subproblema anterior em outros).
fonte
A programação dinâmica é uma técnica para resolver problemas com subproblemas sobrepostos. Um algoritmo de programação dinâmica resolve todos os subproblemas apenas uma vez e salva sua resposta em uma tabela (matriz). Evitando o trabalho de recalcular a resposta sempre que o subproblema for encontrado. A idéia subjacente da programação dinâmica é: Evite calcular o mesmo material duas vezes, geralmente mantendo uma tabela de resultados conhecidos de subproblemas.
As sete etapas no desenvolvimento de um algoritmo de programação dinâmica são as seguintes:
fonte
6. Convert the memoized recursive algorithm into iterative algorithm
uma etapa obrigatória? Isso significaria que sua forma final é não recursiva?em suma, a diferença entre memorização de recursão e programação dinâmica
A programação dinâmica, como o nome sugere, está usando o valor calculado anterior para construir dinamicamente a próxima nova solução
Onde aplicar a programação dinâmica: Se a sua solução for baseada na subestrutura ideal e no subproblema sobreposto, nesse caso, usar o valor calculado anteriormente será útil para que você não precise recalculá-lo. É uma abordagem de baixo para cima. Suponha que você precise calcular fib (n) nesse caso, tudo o que você precisa fazer é adicionar o valor calculado anterior de fib (n-1) e fib (n-2)
Recursão: basicamente subdividindo o problema em uma parte menor para resolvê-lo com facilidade, mas lembre-se de que isso não evita o re-cálculo se tivermos o mesmo valor calculado anteriormente em outra chamada de recursão.
Memorização: Basicamente, o armazenamento do antigo valor de recursão calculado na tabela é conhecido como memorização, o que evitará o recálculo se já tiver sido calculado por alguma chamada anterior, para que qualquer valor seja calculado uma vez. Portanto, antes de calcular, verificamos se esse valor já foi calculado ou não, se já calculado, retornamos o mesmo da tabela em vez de recalcular. Também é abordagem de cima para baixo
fonte
Aqui está um exemplo simples de código python de
Recursive
,Top-down
,Bottom-up
abordagem para a série de Fibonacci:Recursiva: O (2 n )
De cima para baixo: O (n) Eficiente para entrada maior
Bottom-up: O (n) Para simplicidade e tamanhos de entrada pequenos
fonte