Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2276 Accepted Submission(s): 1144
Problem Description
The contest’s message distribution is a big thing in prepare. Assuming N students stand in a row, from the row-head start transmit message, each person can transmit message to behind M personals, and how many ways could row-tail get the message?
Input
Input may contain multiple test cases. Each case contains N and M in one line. (0<=M
Output
Output the ways of the Nth student get message.
Sample Input
4 1
4 2
0 0
Sample Output
1
3
Hint
4 1 : A->B->C->D 4 2 : A->B->C->D, A->C->D, A->B->D
可以说是很水的一道题目了 但是看了一个关于dp的视频之后终于对dp有点理解了 之前对dp一头雾水不知道从哪里下手
一直搜题解报告动态转移方程才能敲出来这样子
直到看了三个题解之后我看了一个视频 (我查了查是七月在线的动态规划实战课,也不是很贵)
dp定义啊之类的网上很多 就不再copy了 我就说说dp的做法吧(也是刚看的视频教程里面说的)
1.先找到最暴力的解法,然后去除冗余(这里我就用最暴力的方法写了一个递归,从上到下的(n到1),感觉从下到上(1到n)很难找到那个关系)
2.设计并存储状态(一维,二维,三维数组,map,其实这里我刚做这个题的时候并没有想到要几维,写完了记忆化搜索动态转移方程基本就出来了)
3.递归式(转移方程)
4.自底向上计算最优解(编程方式)
如果没思路的话,就先写一遍暴力吧!
附代码
#include
#include
using namespace std;
int rf(int m,int n)
{
int sum=0;
if(n==1)
return 1;
for(int i=1;i<=m;++i)
{
if(n-i>=1)
sum+=rf(m,n-i);
}
return sum;
}
int main(void)
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF&&n+m!=0)
{
int h= rf(m,n);
printf("%d\n",h);
}
}
不用说 ,这里的提交肯定是wa了。
这里和别的博客上说的一样,纯暴力会出现许多重叠子问题。
如图(...感觉让我素描老师看见非得骂我不可)(有什么画图软件推荐码!!)
这里用的4,2得例子,这样就会出现(2,2)算了两次 (冗余)当n,m大了之后非常影响效率,如图
所以这里我用了记忆化搜索的方法,就是把结果存起来就可以啦(其实蛮符合刚才提到的第二步)
代码如下
#include
#include
#include
using namespace std;
int dp[35];
int rf(int m,int n)
{
if(dp[n]>0)
return dp[n];
if(n==1)
return 1;
for(int i=1;i<=m;++i)
{
if(n-i>=1)
dp[n]+=rf(m,n-i);
}
return dp[n];
}
int main(void)
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF&&n+m!=0)
{
memset(dp,0,sizeof(dp));
int h= rf(m,n);
printf("%d\n",h);
}
}
这次再提交就过了!
然后都到了这一步了...转移方程也是比较明显了..
dp[j]+=dp[j-i](j-i>=1,i<=m)
继续po代码
#include
#include
#include
using namespace std;
int dp[35];
int main(void)
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF&&n+m!=0)
{
memset(dp,0,sizeof(dp));
dp[1]=1;
for(int i=2;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
if(i-j>=1)
dp[i]+=dp[i-j];
}
}
printf("%d\n",dp[n]);
}
}
好吧..时间上好像没啥优化
这里可能是数据量太小?
emmm初学菜鸡还不是很明白
不过做题思路差不多就是这样啦!