[Wikioi 2618]核电站问题---DP解法与记忆化DFS解法

一个核电站有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是滚雪球式的求解

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值