A idéia básica da programação dinâmica
- algoritmo de programação dinâmica é comumente usado para resolver problemas com alguns dos melhores propriedades. Em tais assuntos, pode haver muitas soluções viáveis. Cada solução corresponde a um valor, esperamos encontrar uma solução com o valor ideal.
- A idéia básica é a de resolver o problema será dividido em vários sub-perguntas, a primeira solução de sub-problema, a solução do problema original e a solução obtida a partir destes sub-temas.
- Adequado sub para resolver problemas de programação dinâmica, o problema muitas vezes é decompostoNão independentes um do outro. Muitos problemas se o número de crianças com um método de dividir e conquistar para resolver este problema, a decomposição de alguns sub-problemas foram contados duas vezes muitas vezes.
- Se pudermos salvar a criança a resposta para o problema foi resolvido, e na necessidade de descobrir as respostas foram obtidas, assim você pode evitar um monte de dupla contagem, economizar tempo. Podemos usar uma tabela para gravar as respostas para todas as sub-problemas têm solução. Se está sendo utilizado no futuro, independentemente das sub-problemas, enquanto calcula-se que ele irá preencher na tabela de resultados.
Passo Programação Projeto Dinâmica
- Propriedades encontrar a solução ideal, e para caracterizar a estrutura em que;
- Definida recursivamente o valor óptimo (equação de programação dinâmico escrito);
- De forma bottom-up calcular o valor ideal;
- A informação obtida quando o cálculo de um valor óptimo construir uma solução óptima.
ps: Etapas 1 a 3 são os passos básicos do algoritmo de programação dinâmica. No caso de um valor ideal requer apenas, passo 4, podem ser omitidos; Para uma solução óptima para o problema exige, passo 4 deve ser realizada.
Características problema de programação dinâmica
A eficácia do algoritmo de programação dinâmica depende de dois natureza importante do problema em si tem:
ideal subestrutura:
Quando a solução ideal contém solução ideal para o problema de seu filho, disse que o problema tem sub-óptima estrutural.
Sobreposição de sub-problemas :
quando um top-down recursiva do algoritmo Solutions, cada sub-problema nem sempre são produzidos novos problemas, alguns sub-problemas são de iterações. algoritmo de programação dinâmica é o uso da natureza sobreposição deste sub-problemas, a solução apenas uma vez para cada sub-problema, e sua solução irá salvar uma tabela, após a solução desses sub-problemas utilizando, tanto quanto possível.
Alguns exemplos típicos
Um problema ainda a multiplicação de matrizes
[Problema]
n matriz Dado {A1, A2, ..., An }, em que Ai e Ai + 1 é multiplicativo, i = 1,2 ..., N- 1. Como determinar o cálculo da matriz de cálculo até mesmo encomendar o produto, tornando o produto ainda nesta ordem da multiplicação de matrizes para calcular o número mínimo exigido?
[Análise]
O produto de matriz ainda AiAi + 1 Aj ... abreviado como A [i: j], onde i≤j; Um cálculo investigado [1: N] ordem óptimo calculado.
Esta sequência é fornecida entre as matrizes calculados Ak e Ak + 1 cadeia matriz é quebrado, 1≤k <n, o modo correspondente está completamente suportado (A1A2 ... Ak) (Ak + 1Ak + 2 ... An).
Um cálculo: melhor ordem de [1 n] está incluído na filha do Fio Calculada matriz A [1: k] e A [k + 1: n] é a melhor ordem.
Cálculo: A [1: k] quantidade calculada além Um [k + 1: N] de cálculo, A? [1: k] Plus e uma [K + 1: n] é calculado multiplicando-se a quantidade de
[método]
desenho do estudo a [i: j], 1≤i≤j≤n , mais por um pequeno número de vezes m [i, j] requerido, o valor óptimo do problema original m [1, n]
quando i quando j =, a [i: j] = Ai, e, por conseguinte, m [i, i] = 0, i = 1,2, ..., n
ao i <j, a
pode ser definida recursivamente m [i, j] é :
[] complexidade vez
[Código]
#include<bits/stdc++.h>
using namespace std;
#define NUM 51
int p[NUM],n;
int m[NUM][NUM];
int s[NUM][NUM];
int main()
{
cin>>n;
for(int i=0; i<=n; i++)
cin>>p[i];
for(int r=2; r<=n; r++)
for(int i=1; i<=n-r+1; i++)
{
int j=i+r-1;//计算初值,从i处断开
m[i][j] = m[i+1][j]+p[i-1]*p[i]*p[j];
s[i][j] = i;
for(int k=i+1; k<j; k++)
{
int t = m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
if (t < m[i][j])
{
m[i][j] = t;
s[i][j] = k;
}
}
}
cout<<m[1][n]<<endl;
return 0;
}
algoritmo recursivo:
int Recurve(int i, int j)
{
if(i==j)
return 0;
int u=Recurve(i, i)+Recurve(i+1,j)+p[i-1]*p[i]*p[j];
s[i][j]=i;
for(int k=i+1; k<j; k++)
{
int t=Recurve(i, k)+Recurve(k+1,j)+p[i-1]*p[k]*p[j];
if (t<u)
{
u=t;
s[i][j]=k;
}
}
m[i][j]=u;
return u;
}
Memorando de algoritmos:
algoritmo de programação dinâmica como memorando maneira de salvar a criança responde perguntas foram resolvidos com uma mesa, quando nos deparamos com a criança problema, simplesmente para encontrar respostas para as sub-problemas, sem ter que resolvido.
int LookupChai (int i, int j)
{
if(m[i][j]>0)
return m[i][j];
if(i==j)
return 0;
int u=LookupChain(i,i)+LookupChain(i+1,j)+p[i-1]*p[i]*p[j];
s[i][j]=i;
for(int k=i+1; k<j; k++)
{
int t=LookupChain(i,k)+LookupChain(k+1,j)+p[i-1]*p[k]*p[j];
if (t<u)
{
u=t;
s[i][j]=k;
}
}
m[i][j] = u;
return u;
}
Em segundo lugar, o mais longo subsequência comum
[Problema]
Se uma dada sequência X = {x1, x2, ... ,} xm, em seguida, uma outra sequência Z = {z1, z2, ... , zk}, X é uma subsequência refere-se à presença o subscrito uma sequência estritamente crescente {I1, I2, ..., ik } de tal modo que para todos os j = 1,2, ..., k têm: zj = xij.
Dadas duas sequências X e Y, Z, quando a subsequência outra sequência de ambos X e Y é uma subsequência de tempo, que o referido Z é uma sequência de X e Y subsequência comum .
Dadas duas sequências X = {x1, x2, ... , xm} e Y = {y1, y2, ... , yn}, para encontrar o mais longo subsequência comum de X e Y são. E a saída dessa sequência.
[Análise]
reinicialização sequência X = {x1, x2, ... , xm} e Y = {y1, y2, ... , yn} é a mais longa comum subsequência Z = {z1, z2, ... , z k}, em seguida,
1) Se xm = yn, em seguida, zk = XM = yn, e ZK-1 xm-1 é a mais longa soma comum subsequência yn-1.
2) Se o xm ≠ yn e ZK ≠ xm, então Z é o mais longo subsequência comum XM-1 e Y.
3) Se o xm ≠ yn yn e ZK ≠, então Z e X in-1 é a subsequência comum mais longo.
A saber:
[code]
#include<bits/stdc++.h>
using namespace std;
int n,m;
char a[10010],b[10010];
int dp[10010][10010],x[10010][10010];
vector<char>v;
void LCS(int i,int j)
{
if(i==0||j==0)
return;
if(x[i][j]==1)
{
LCS(i-1,j-1);
v.push_back(a[i]);
}
else if (x[i][j]==2)
LCS(i-1,j);
else
LCS(i,j-1);
}
int main()
{
cin>>n>>m;
for(int i=1; i<=n; i++)
cin>>a[i];
for(int i=1; i<=m; i++)
cin>>b[i];
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
if(a[i]==b[j])
{
dp[i][j]=dp[i-1][j-1]+1;
x[i][j]=1;
}
else if (dp[i-1][j]>=dp[i][j-1])
{
dp[i][j]=dp[i-1][j];
x[i][j]=2;
}
else
{
dp[i][j]=dp[i][j-1];
x[i][j]=3;
}
}
}
cout<<dp[n][m]<<endl;
LCS(n,m);
for(int i=v.size()-1;i>=0;i--)
cout<<v[i]<<" ";
cout<<endl;
return 0;
}
Em terceiro lugar, o sub-segmento e o máximo
[problemas]
a uma sequência determinada pelo a1 n inteiros (incluindo números inteiros negativos) que consiste em, A2, ..., An, seleccionando o valor máximo e a sequência de sub-segmentos.
Defina seu maior sub-segmento quando todos são inteiros negativos e zero.
Os valores ideais requeridos:
[Análise]
bj é a maior posição sub-segmento e j a 1:
fácil saber definido por bj, se bj-1> 0 quando bj = bj-1 + aj, caso contrário bj = aj.
Bj é calculado recursão de programação dinâmica: bj = max {bj-1 + AJ, AJ}, 1≤j≤n.
[Código]
#include<bits/stdc++.h>
using namespace std;
int n,a[100010];
int b,sum,l,r,s;
int main()
{
cin>>n;
for(int i=1; i<=n; i++)
cin>>a[i];
for(int i=1; i<=n; i++)
{
if(b>0)
b+=a[i];
else{
b=a[i];
s=i;
}
if(b>sum)
{
sum=b;
r=i;
l=s;
}
}
cout<<l<<" "<<r<<" "<<sum<<endl;
return 0;
}
Em quarto lugar, o problema da mochila 0-1
[Problema]
Dado um conjunto de itens s = {1,2,3, ..., n }, o peso do item i wi é, o valor é VI, capacidade mochila de W, isto é, a carga máxima pesando não mais de W. Dentro de um total limitado W peso, como podemos escolher itens, a fim de fazer o valor máximo total dos itens.
Se o item não pode ser dividida, isto é, quer o artigo inteiro i ao seleccionar ou não seleccionar; artigo i dentro de um saco não pode ser repetidamente, apenas uma parte do artigo não pode ser carregada com i, em seguida, o problema é chamado 0-1 problema da mochila.
Se o item pode ser dividido, então o problema é chamado problema da mochila, algoritmo guloso adequado para uso.
[Análise]
i≤k≤n valor ideal de p (i, j).
Mochila capacidade j, é um item opcional i, i + 1, ..., n o valor ideal quando o problema 0-1 mochila.
[Código]
#include<bits/stdc++.h>
using namespace std;
int n,m;
int f[100010],w[100010],v[100010];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>w[i]>>v[i];
memset(f,0,sizeof(f));
f[0]=0;
for(int i=1; i<=n; i++)
for(int j=m; j>=w[i]; j--)
f[j]=max(f[j],f[j-w[i]]+v[i]);
int ans=0;
for(int j=0; j<=m; j++)
ans=max(ans,f[j]);
cout<<ans<<endl;
return 0;
}