1.题目
http://acm.hdu.edu.cn/showproblem.php?pid=2151
2.分析
题目给出初始位置P,然后每分钟都从上一次能到达的位置开始向左右两边扩展,同时记录转移的方案书,这是典型的直接模拟的思路。此时对于动态规划思想的运行指示限定在存储了上一分钟的中间结果。
动态规划使用的决策为:相邻果树的数值之和,按照时间顺序和位置考虑最优子结构和重叠子问题;
3.复杂度
两重循环,时间复杂度为O(MN);空间复杂度为O(N);
4.涉及内容
算法:动态规划
5.感想
每次从上一次能到达的位置开始向左右两边扩展,按照直接模拟的思路来做的时候,代码长度较长。应该按照“动态规划”的思想来解题,这样方便理解,并且代码较短。
6.代码
#include <iostream>
using namespace std;
class Hdu2151{
public:
int N,P,M,T;
bool oldisreach[101],newisreach[101];
long oldcount[101],newcount[101];
void init(int n,int p,int m,int t)
{
this->N=n;this->P=p;this->M=m;this->N=n;this->T=t;
memset(oldisreach,0,101*sizeof(bool));memset(newisreach,0,101*sizeof(bool));
memset(oldcount,0,101*sizeof(long));memset(newcount,0,101*sizeof(long));
oldisreach[P]=true; oldcount[P]=1;
}
void backtract()
{
for(int i=0;i<M;++i)
{
for(int j=1;j<=N;++j)
{
if(oldisreach[j])
{
newisreach[j-1]=newisreach[j+1]=true;
newcount[j-1]+=oldcount[j];
newcount[j+1]+=oldcount[j];
}
}
for(int j=1;j<=N;++j)
{
oldisreach[j]=newisreach[j];
oldcount[j]=newcount[j];
}
memset(newisreach,0,101*sizeof(bool));
memset(newcount,0,101*sizeof(long));
}
}
void print(int n,int p,int m,int t)
{
init(n,p,m,t);
backtract();
cout<<oldcount[T]<<endl;
}
};
int main()
{
Hdu2151 hdu2151;
int N,P,M,T;
while(cin>>N>>P>>M>>T)
{
hdu2151.print(N,P,M,T);
}
return 0;
}
7.参考文献
参考按照动态规划的思路写的代码:
#include<stdio.h>
#include<string.h>
int max(int x,int y)
{return x>y?x:y;}
int dp[105][105];
int main()
{
int n,p,m,t,i,j;
while(scanf("%d%d%d%d",&n,&p,&m,&t)!=EOF)
{
memset(dp,0,sizeof(dp));
dp[0][p]=1;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
dp[i][j]=max(dp[i][j],dp[i-1][j-1]+dp[i-1][j+1]);
printf("%d\n",dp[m][t]);
}
return 0;
}