最近在碰到一个这样的题目,但是这个我认为就是动态规划里面比较难的题目了。
动态规划,其实我认为其实就是类似于高中的数列里面的递推公式,只不过是在递推的过程中增加了一些判断条件(就像本题)。
解决动态规划的问题的步骤大致可以分为三种:
一,理解dp的含义
二,推理出递推公式
三,找出初始值。
想要具体的了解这三个步骤的含义,可以参考这篇博客。
下面来分析本题:
一,设置dp[i],这里一定要理解,dp[i]是指从原点到第i个点的最大的分数。本题中的对dp的初始化在代码中有相应的注释
二,推理出递推公式,本题中的推理公式就需要有一定的判断条件。判断条件就是if(chessmen(j)<chessmen(i)) 之后才能执行 dp[i] = max(dp[i],dp[j] + chessmen[i]),解释一下这个含义,dp[i]原本代表的是到 i 的位置已知的所能得到的最大的分数,dp[j] + chessmen[i]的意思则是在位置 j 到 i 的位置的所添加新的分数,从而找到这个最大的分数。最终循环完了之后就可以找到这个最大的分数
三,找出初始值。本题中的初始值不必找,因为这个在一开始我就定义了dp[i]的初始值,就不必再找初始值。
下面来看代码,代码中有更有详细的注释
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN = 1005;
int main()
{
int N;
int chessmen[MAXN];
int dp[MAXN];//动态规划,这个dp[i]代表的是从原点到第i个的最大值。
//dp[i] = max(dp[i],.dp[j]+chessmen[i]);//第一个dp[i]的含义是从原点直接到达这个点所得到的分数
while(1)
{
cin>>N;
if(!N)
break;
memset(dp,0,sizeof(dp));//全部初始化
for(int i =1;i<=N;i++)
{
cin>>dp[i];// dp[i]一开始代表的是从原点直接跳到这个位置所得到的分数
chessmen[i] = dp[i];
}
int maxmum = dp[0]; // = 0
for(int i = 1;i<=N;i++)
{
for(int j = 1;j<i;j++)//这里的不能是<= 因为不能从自己跳到自己
if(chessmen[j]<chessmen[i])
dp[i] = max(dp[i],dp[j]+chessmen[i]);
if(maxmum<dp[i])
maxmum = dp[i];
}
cout<<maxmum<<endl;
}
return 0;
}
另外再附上杭电OJ上的另外一题:编号2062
这个题目的三个含义读者可以自己先找找
#include <stdio.h>
int main() {
long long num_perGroup[21],m;//num_perGroup:下标i中每组的个数,比如num_perGroup[3]=5
int n,i,group,print_num[21];//print_num是根据计算出的位置打印数
num_perGroup[1] = 1;
for (i = 2; i <= 20 ; ++i)//根据前文推理的公式,初始化每组个数
num_perGroup[i] = (i-1) * num_perGroup[i - 1] + 1;
while (scanf("%d%lld",&n,&m)!=EOF){
for (i = 1; i <=20 ; ++i)//初始化打印数,打印第i个位置就是i,随着输出进行,其会发生变化
print_num[i] = i;
while (m){//当m更新为0时就不需要再打印即退出
group = (m-1)/num_perGroup[n] + 1;//计算当前打印数,即计算为第几组,
printf("%d",print_num[group]);//根据组号打印
for (i = group; i < 20 ; ++i)//打印后,把打印完的覆盖,之后不会在打印
print_num[i] = print_num[i+1];
m = m % num_perGroup[n];//计算在组内的位置
if(m==0)//在最后一个位置
m = num_perGroup[n];
m--;//去除第一个不要任何数跟着的情况比如{3}{2}{1},这在后续迭代中很重要,否则会计算组数错误。
n--;//打印出了一个,因此n要减去一个
if(m)//判断是否打印完
printf(" ");
else
printf("\n");
}
}
}