适合用动态规划的问题特征:可以分解成相互重叠的若干子问题; 满足最优性原理(结构性质):该问题的最优解中也包含着其子问题的最优解。一般地,子问题的联系体现在某种递推关系,通过这种递推计算可以把问题的解存储起来,后期直接使用,避免重复运算。
简单的dp例子:http://acm.nefu.edu.cn/JudgeOnline/problemshow.php?problem_id=20
递推关系:m[i][j]=m[i-1][j]+m[i][j-1]
#include <iostream>
#include<cstdio>
using namespace std;
int main()
{
int i,j,m[20][20],n;
for(i=1;i<16;i++){
m[i][0]=1;
m[0][i]=1;
}
for(i=1;i<16;i++){
for(j=1;j<16;j++){
m[i][j] = m[i-1][j]+m[i][j-1];
}
}
while(cin>>n&&n){
printf("%d\n",m[n][n]);
}
return 0;
}
再来一个: http://acm.nefu.edu.cn/JudgeOnline/problemshow.php?problem_id=91
递推关系题目已经说明了,不用我们去研究,现在要解决的是如何判断“新产生的数字没有在之前出现过”,最快的方法:以空间换取时间,用一个标记数组来快速判断。
#include <iostream>
#include<cstdio>
using namespace std;
const int maxn=5e5+5;
bool judge[maxn*100]; //估计的大小,标记数组
int number[maxn];
int main()
{
int i,k;
judge[0]=1; number[0]=0;
for(i=1;i<maxn+1;i++){
int t=number[i-1]-i;
if(t>0&&judge[t]==0){
number[i]=t;
judge[t]=1;
}
else {
number[i]=number[i-1]+i;
judge[number[i]]=1;
}
}
while(cin>>k&&k!=-1){
printf("%d\n",number[k]);
}
return 0;
}