[DP]逃生

本题选自计蒜客动态规划习题

【题目描述】

        蒜头君在玩一款逃生的游戏。在一个n×m的矩形地图上,蒜头位于其中一个点。地图上每个格子有加血的药剂,和掉血的火焰,药剂的药效不同,火焰的大小也不同,每个格子上有一个数字,如果格子上的数字是正数说明是一个药剂代表增加的生命值,如果是负数说明是火焰代表失去的生命值。 蒜头初始化有v点血量,他的血量上限是c,任何时刻他的生命值都不能大于血量上限,如果血量为0则会死亡,不能继续游戏。

        矩形地图上的四个角(1,1),(1,m),(n,1),(n,m)为游戏的出口。游戏中只要选定了一个出口,就必须朝着这个方向走。例如,选择了左下的出口,就只能往左和下两个方向前进,选择了右上的出口,就只能往右和上两个方向前进,左上和右下方向的出口同理。 如果成功逃生,那么剩余生命值越高,则游戏分数越高。为了能拿到最高分,请你帮忙计算如果成功逃生最多能剩余多少血量,如果不能逃生输出-1。

【输入格式】

        第一行依次输入整数n,m,x,y,v,c(1<n,m≤1000,1≤x≤n,1≤y≤m,1≤v≤c≤10000),其中n,m代表地图大小,(x,y)代表蒜头君的初始位置,v代表蒜头的初始化血量,c代表蒜头的生命值上限。 接下来n行,每行有m个数字,代表地图信息。(每个数字的绝对值不大于100, 地图中蒜头君的初始位置的值一定为0)

【输出格式】 一行输出一个数字,代表成功逃生最多剩余的血量,如果失败输出-1。

【样例输入】

4 4 3 2 5 10

1 2 3 4

-1 -2 -3 -4

4 0 2 1

-4 -3 -2 -1

【样例输出】

10

【分析】(个人观点,仅供参考)

        此题特意设置4个出口,相当于把4个方向的迷宫问题组合在一起。

        因此,可以考虑分别进行四个方向的动态规划,将到达4个出口的最大值输出。

        因为不想写四段程序,所以简化了记忆化搜索(即便如此,还有8个方向需要判断),根据(i, j) 与起点 (x, y) 的相对位置,判断当前走向,调用状态转移方程。 和 (x, y) 同行同列的点,只能由单一方向过来,故需要单独考虑。

        搜索过程如果遇到血量为 0 的情况,可以将状态值设置为极小值,避免影响结果;

        如果超过血量上限,则更新血量为上限值 c。

        ans 初始化为 -1,如果没有血量更高的出口,则保持 -1 输出。

#include<iostream>
using namespace std;
int a[1001][1001], dp[1002][1002], ans= -1,n,m,x,y,v,c;

int dfs(int i,int j){       //返回 到 a[i][j] 的最大血量
    if(dp[i][j])  	return dp[i][j];      //该点已经计算过
	
	if(i<x && j==y)		dp[i][j] = dfs(i+1,j) +a[i][j];	//计算同行同列
	else if(i>x && j==y)	dp[i][j] = dfs(i-1,j) +a[i][j];			 
	else if(i==x && j<y)	dp[i][j] = dfs(i,j+1) +a[i][j];
	else if(i==x && j>y)	dp[i][j] = dfs(i,j-1) +a[i][j];	
	else if(i>x && j>y)	dp[i][j] = max( dfs(i-1,j), dfs(i,j-1) ) + a[i][j];  //出口在右下方 
	else if(i>x && j<y)	dp[i][j] = max( dfs(i-1,j), dfs(i,j+1) ) + a[i][j];  //出口在左下方 
	else if(i<x && j>y)	dp[i][j] = max( dfs(i+1,j), dfs(i,j-1) ) + a[i][j];  //出口在右上方 
	else if(i<x && j<y)	dp[i][j] = max( dfs(i+1,j), dfs(i,j+1) ) + a[i][j];  //出口在左上方 	
	if(dp[i][j]<=0)  dp[i][j]= -2000000000;  //已死亡
	if(dp[i][j]>c)  dp[i][j]= c;      //超血量
	return dp[i][j];
}

int main(){
	cin>>n>>m>>x>>y>>v>>c;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&a[i][j]);
	dp[x][y] = a[x][y]+v;   //记录起点的初始体力 ,放入状态数组
	ans  = max( ans, dfs(1,1) ) ;
	ans  = max( ans,dfs(1,m) ) ;
	ans  = max( ans, dfs(n,1) ) ;
	ans  = max( ans,dfs(n,m) ) ;    
	cout<<ans;
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值