题目描述 Description
一个核电站有N个放核物质的坑,坑排列在一条直线上。如果连续M个坑中放入核物质,则会发生爆炸,于是,在某些坑中可能不放核物质。
任务:对于给定的N和M,求不发生爆炸的放置核物质的方案总数。
输入描述 Input Description
输入文件只一行,两个正整数N,M( 1<N<50,2≤M≤5)
输出描述 Output Description
输出文件只有一个正整数S,表示方案总数。
样例输入 Sample Input
4 3
样例输出 Sample Output
13
数据范围及提示 Data Size & Hint
( 1<N<50,2≤M≤5)
题目思路
不管是用记忆化DFS还是DP做,都要用一个数组f保存当前结果,f[n][m]=前n个坑最后已经连续放m个核材料的方案数,而且要注意数组的初始化,即f[0][0]=1
1、记忆化DFS解法
#include <stdio.h>
#define LONG long long int
#define MAXN 1000
LONG n,m,sum=0;
LONG f[MAXN][MAXN]; //f[n][m]=前n个坑最后已经连续放m个核材料的方案数
LONG dfs(LONG x,LONG k) //获得第x个坑是连续放第k个核材料的方案数
{
int i,j;
if(x<k) return 0;
if(f[x][k]!=0) return f[x][k];
if(k>=1) f[x][k]=dfs(x-1,k-1); //如果k>=1,那么第x个坑是连续放第k个核材料的方案数=第x-1个坑是连续放k-1个核材料的方案数
else //k=0,第x个坑不放核材料,那么f[x][k]=sum{f[x-1][i]},0<=i<m
{
for(i=0;i<m;i++)
f[x][k]+=dfs(x-1,i);
}
return f[x][k];
}
int main()
{
int i,j;
scanf("%lld%lld",&n,&m);
f[0][0]=1;
//f[n][m]=sum{f[n][i]},0<=i<m
for(i=0;i<m;i++)
{
sum+=dfs(n,i);
}
printf("%lld\n",sum);
return 0;
}
由上面的记忆化DFS解法,分析搜索过程及判断条件,不难推出DP方程:
(i) k=0,f[x][k]=sum{f[x-1][i]},x>=k&&0<=i<m
(ii) k>0,f[x][k]=f[x-1][k-1],x>=k
DP前同样要注意初始化问题,同上
2、DP解法
#include <stdio.h>
#define LONG long long int
#define MAXN 1000
LONG n,m,sum=0;
LONG f[MAXN][MAXN]; //f[n][m]=前n个坑最后已经连续放m个核材料的方案数
int main()
{
int i,j,k,x;
scanf("%lld%lld",&n,&m);
f[0][0]=1;
f[1][0]=1;
f[1][1]=1;
//k=0,f[x][k]=sum{f[x-1][i]},x>=k&&0<=i<m
//k>0,f[x][k]=f[x-1][k-1],x>=k
for(x=2;x<=n+1;x++)
{
for(k=0;k<m&&k<=x;k++)
{
if(k==0)
{
for(i=0;i<m;i++)
f[x][0]+=f[x-1][i];
}
else
f[x][k]=f[x-1][k-1];
}
}
printf("%lld\n",f[n+1][0]);
return 0;
}
记忆化搜索的效果接近DP,但从测试结果上看,DP还是比记忆化搜索快不少,而且代码也短很多,毕竟DP是滚雪球式的求解