51nod 1489 蜥蜴和地下室(dfs or dp)

题目来源:  CodeForces
基准时间限制:1 秒 空间限制:131072 KB 分值: 10  难度:2级算法题
 收藏
 关注

哈利喜欢玩角色扮演的电脑游戏《蜥蜴和地下室》。此时,他正在扮演一个魔术师。在最后一关,他必须和一排的弓箭手战斗。他唯一能消灭他们的办法是一个火球咒语。如果哈利用他的火球咒语攻击第i个弓箭手(他们从左到右标记),这个弓箭手会失去a点生命值。同时,这个咒语使与第i个弓箭手左右相邻的弓箭手(如果存在)分别失去b(1 ≤ b < a ≤ 10)点生命值。

因为两个端点的弓箭手(即标记为1和n的弓箭手)与你相隔较远,所以火球不能直接攻击他们。但是哈利能用他的火球攻击其他任何弓箭手。

每个弓箭手的生命值都已知。当一个弓箭手的生命值小于0时,这个弓箭手会死亡。请求出哈利杀死所有的敌人所需使用的最少的火球数。

如果弓箭手已经死亡,哈利仍旧可以将他的火球扔向这个弓箭手。


Input
第一行包含3个整数 n, a, b (3 ≤ n ≤ 10; 1 ≤ b < a ≤ 10),第二行包含n个整数——h1,h2,...,hn (1 ≤ hi ≤ 15), hi 是第i个弓箭手所拥有的生命力。
Output
以一行输出t——所需要的最少的火球数。
Input示例
3 2 1
2 2 2
Output示例
3



dfs:


代码如下:


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 12;
const int INF = 0x3f3f3f;
int h[maxn];
int n,a,b,ans,Min;

void dfs(int x,int res)
{
	if(x==n)
	{
		Min=min(Min,res);
		return ;
	}
	if(h[x-1]<0)
		dfs(x+1,res);
	int cnt=0;
	if(h[x-1]>=0)
	{
		cnt=h[x-1]/b+1;
		h[x-1]-=cnt*b;
		h[x]-=cnt*a;
		h[x+1]-=cnt*b;
		dfs(x+1,res+cnt);
		h[x-1]+=cnt*b;
		h[x]+=cnt*a;
		h[x+1]+=cnt*b;
	}
	int num=h[x]/a+1;
	if(h[x]>=0 && cnt<num)//当消灭x-1位置的次数可以在cnt和num之间时,暴搜找到最合适的次数 
	{
		for(int i=cnt+1;i<=num;++i)
		{
			h[x-1]-=b*i;
			h[x]-=a*i;
			h[x+1]-=b*i;
			dfs(x+1,res+i);
			h[x-1]+=b*i;
			h[x]+=a*i;
			h[x+1]+=b*i;
		}
	}
	return ;
}

int main()
{
	while(scanf("%d%d%d",&n,&a,&b)!=EOF)
	{
		ans=0; Min=INF;
		for(int i=1;i<=n;++i)
			scanf("%d",&h[i]);
		int cnt=h[1]/b+1;//先消灭第1个和最后一个 
		ans+=cnt;
		h[1]-=b*cnt;
		h[2]-=a*cnt;
		h[3]-=b*cnt;
		if(h[n]>=0)
		{
			cnt=h[n]/b+1;
			ans+=cnt;
			h[n]-=b*cnt;
			h[n-1]-=a*cnt;
			h[n-2]-=b*cnt;
		}
		dfs(2,0);
		if(Min==INF)
			Min=0;
		printf("%d\n",ans+Min);
	}
	return 0;
} 



dp


代码如下:


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f;
int h[12];
int dp[12][18][18][18]; //表示在x位置时,x-1,x,x+1位置的生命值分别为i,j,k时候的最小攻击次数 
int main()
{
	int n,a,b;
	while(scanf("%d%d%d",&n,&a,&b)!=EOF)
	{
		for(int i=1;i<=n;++i){
			scanf("%d",&h[i]);
			h[i]++;//保证值为0的时候就被消灭了 
		}
		for(int x=0;x<12;++x)
			for(int i=0;i<=16;++i)//注意初始化,i<16会WA 
				for(int j=0;j<=16;++j)
					for(int k=0;k<=16;++k)
						dp[x][i][j][k]=INF;
		dp[1][0][h[1]][h[2]]=dp[2][h[1]][h[2]][h[3]]=0;
		for(int x=2;x<n;++x)
			for(int i=h[x-1];i>=0;--i)
				for(int j=h[x];j>=0;--j)
					for(int k=h[x+1];k>=0;--k)
					{
						int ii = max(0,i-b);
						int jj = max(0,j-a);
						int kk = max(0,k-b);
						dp[x][ii][jj][kk] = min(dp[x][ii][jj][kk], dp[x][i][j][k]+1);
						if(i==0)
							dp[x+1][j][k][h[x+2]] = min(dp[x+1][j][k][h[x+2]], dp[x][i][j][k]);//可以攻击x+1位置,消灭x位置的敌人 
						if(ii==0)
							dp[x+1][jj][kk][h[x+2]] = min(dp[x+1][jj][kk][h[x+2]], dp[x][i][j][k]+1);//保证第x-1位置敌人被消灭才能进入下一步	
					}
		printf("%d\n",dp[n][0][0][0]);	
	}
	return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值