一个核电站有N个放核物质的坑,坑排列在一条直线上。如果连续M个坑中放入核物质,则会发生爆炸,于是,在某些坑中可能不放核物质。
任务:对于给定的N和M,求不发生爆炸的放置核物质的方案总数。
输入文件只一行,两个正整数N,M( 1<N<50,2≤M≤5)
输出文件只有一个正整数S,表示方案总数。
4 3
13
( 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是滚雪球式的求解