Como você identifica um problema como adequado para programação dinâmica?

19

Ultimamente, tenho lido sobre programação dinâmica. Gostaria de ouvir alguém que começou do zero e agora é muito bom em identificar e resolver problemas de DP. Estou lutando para identificar esses problemas como DP e estruturar uma solução concisa.

Passei pela maioria dos problemas de DP iniciantes e recursos do MIT, etc.

user110036
fonte

Respostas:

17

Eu venho de uma formação em física e, portanto, muita matemática. Acho fácil identificar problemas bem adequados para soluções de programação dinâmica / recursiva, encontrando semelhanças com provas por indução .

Na prova por indução, você tem duas partes:

  • você prova que, se algo é verdadeiro para a iteração N, também é verdade para a iteração N + 1
  • você prova que é verdade para a iteração 1

Na programação recursiva / programação dinâmica:

  • você identifica uma condição de saída (por exemplo, conecta a solução para a iteração 1)
  • você calcula a solução para a iteração N, dada a solução para a iteração N-1

Portanto, como outros responderam, é uma questão de experiência e escolha das dicas, mas você pode reutilizar outras habilidades para guiá-lo. Depois disso, você precisa sempre ter as duas partes que mencionei: se não o fizer, não funcionará.

Por exemplo, para gerar todas as permutações de um conjunto:

  • condição de saída: se você tiver apenas um elemento, retorne-o
  • recursão: as permutações de um conjunto de N itens são os N conjuntos de permutações que você obtém escolhendo cada elemento e combinando-o com todos os conjuntos N-1 de (muitas) permutações do subconjunto obtido removendo o elemento.
Sklivvz
fonte
8

A maioria dos problemas de programação dinâmica pode ser resolvida através de memorização. A memorização é normalmente mais intuitiva e fácil de codificar. Você pode achar útil pensar em termos de memorização em vez de DP.

Geralmente é mais fácil intuir se um problema é adequado à memorização (os passos são os mesmos da resposta de Slivvz , mas acho que a mudança mental é um pouco mais curta). No entanto, depois de resolver um problema via memorização, você pode examinar como o cache de notas está sendo preenchido e preenchê-lo em ordem, sem recursão ... o que altera seu algoritmo para um algoritmo de programação dinâmico.

TL; DR; versão: você pode achar mais fácil entender a programação dinâmica em termos de memorização.

Consulte também StackOverflow: programação dinâmica e memorização: abordagens de baixo para cima e de cima para baixo .

Brian
fonte
4

A programação dinâmica é definitivamente sobre duas coisas:

  1. Subestrutura ideal
    Soluções maiores podem ser derivadas de soluções menores; resolver não é bidirecional.

  2. Subproblemas sobrepostos
    As pequenas soluções serão reutilizadas várias vezes. Se os subproblemas não se sobrepõem, você não se beneficia da DP / memória; o que você tem é dividir e conquistar .

A abordagem geral dos problemas de DP é:

  • Escreva uma versão recursiva ou iterativa ingênua que funcione.

  • Observe que a função está executando um trabalho redundante.

  • Encontre uma maneira de evitar fazer esse trabalho redundante, geralmente por memória.

Jon Purdy
fonte
Tudo isso é verdade do ponto de vista teórico. IMO um pouco de prática mais é necessário para ser mais familiar na identificação rápida :)
user110036
2

Eu nunca havia implementado um único solucionador de programação dinâmica - meu conhecimento é aplicado em matemática / física / computação numérica, não em CS - até alguns anos atrás, quando comecei a fazer problemas no Project Euler . Os problemas solucionáveis ​​por DP (por exemplo , 76 , 158 , 161 , 242, mas há muito mais) acabou sendo o meu tipo favorito. Você definitivamente fica melhor identificando quando será uma técnica útil: basicamente, procure coisas que parecem poder ser resolvidas por algum tipo de abordagem recursiva de dividir e conquistar, onde também é possível domar a explosão de caminhos que precisam ser explorado reconhecendo subproblemas recorrentes e reutilizando os resultados calculados anteriormente; ser capaz de identificar o vetor de estado mínimo para memorizar - e que "história" irrelevante pode ser apagada - é o passo crucial.

timday
fonte