HDU4826 - Labyrinth(棋盘DP)

本文介绍了一种基于动态规划的迷宫寻宝算法,旨在帮助角色在限制条件下收集尽可能多的金币。通过分析不同路径的选择策略,文章提供了一种有效的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接http://acm.hdu.edu.cn/showproblem.php?pid=4826

【题目】

Problem Description
  
度度熊是一只喜欢探险的熊,一次偶然落进了一个m*n矩阵的迷宫,该迷宫只能从矩阵左上角第一个方格开始走,只有走到右上角的第一个格子才算走出迷宫,每一次只能走一格,且只能向上向下向右走以前没有走过的格子,每一个格子中都有一些金币(或正或负,有可能遇到强盗拦路抢劫, 度度熊身上金币可以为负,需要给强盗写欠条),度度熊刚开始时身上金币数为0,问度度熊走出迷宫时候身上最多有多少金币?
 
Input
  
输入的第一行是一个整数T(T < 200),表示共有T组数据。 每组数据的第一行输入两个正整数m,n(m<=100,n<=100)。接下来的m行,每行n个整数,分别代表相应格子中能得到金币的数量,每个整数都大于等于-100且小于等于100。
 
Output
  
对于每组数据,首先需要输出单独一行”Case #?:”,其中问号处应填入当前的数据组数,组数从1开始计算。 每组测试数据输出一行,输出一个整数,代表根据最优的打法,你走到右上角时可以获得的最大金币数目。
 
Sample Input
  
2 3 4 1 -1 1 0 2 -2 4 2 3 5 1 -90 2 2 1 1 1 1
 
Sample Output
  
Case #1: 18 Case #2: 4

 

 

【分析】和经典的从左上角走到右下角取最大值类似的,只是可以往三个方向走,导致DP顺序有点难找;

首先,对于往右走这个方向,由于不能往左走,所以只要按照列(j)从左往右DP就能保证先算出左边的DP;对于第一列,只能往下走,所以直接初始化,DP从第二列开始。

主要难点是对与可以上下两个方向走动的,对于行(i)的顺序是先算上还是先算下面的,都不行。这时需要在DP过程中,分别算出左边的,上面的和下面的只,选择最大的那个,

然后在计算上下两个方向的时候要每次都和左边过来的值比较选择最优的一个,得到最优值只要比较上下两个方向的最大值就可以了,具体看代码。

 

【AC代码】46ms

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 110
int a[MAXN][MAXN], dp[MAXN][MAXN], h, w;

int main ()
{
#ifdef SHY
	freopen("e:\\1.txt","r",stdin);
#endif
	int t, count = 0;
	scanf ("%d%*c" ,&t);
	while(t--)
	{
		scanf ("%d %d%*c", &h, &w);
		for (int i = 1; i <= h; i++)
		{
			for (int j = 1; j <= w; j++)
				scanf ("%d%*c", &a[i][j]);
		}
		memset(dp,-0x3f,sizeof(dp));
		dp[0][1] = 0;
		for (int i = 1; i <= h; i++)
			dp[i][1] = a[i][1]+dp[i-1][1];
		int buf[MAXN][2];//buf[][1]记录从上方走来的当前最大价值,buf[][1]记录下方走来的当前最大价值
		for (int j = 2; j <= w; j++)
		{
			for (int i = 1; i <= h; i++)//记录从左边走来的价值
				dp[i][j] = dp[i][j-1]+a[i][j];
			buf[1][0] = dp[1][j];
			for (int i = 2; i <= h; i++)//每次都要比较从左边还是上面走来大
				buf[i][0] = max(dp[i][j],buf[i-1][0]+a[i][j]);
			buf[h][1] = dp[h][j];
			for (int i = h-1; i >= 1; i--)//每次都要比较从左边还是下面走来大
				buf[i][1] = max(dp[i][j],buf[i+1][1]+a[i][j]);
			for (int i = 1; i <= h; i++)//找到最大值
				dp[i][j] = max(buf[i][0],buf[i][1]);
		}
		printf ("Case #%d:\n%d\n", ++count, dp[1][w]);
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值