hdu 4826

hdu 4826

题意

度度熊是一只喜欢探险的熊,一次偶然落进了一个 $ m * n $ 矩阵的迷宫,该迷宫只能从矩阵左上角第一个方格开始走,只有走到右上角的第一个格子才算走出迷宫,每一次只能走一格,且只能向上向下向右走以前没有走过的格子,每一个格子中都有一些金币(或正或负,有可能遇到强盗拦路抢劫,度度熊身上金币可以为负,需要给强盗写欠条),度度熊刚开始时身上金币数为0,问度度熊走出迷宫时候身上最多有多少金币?

解法

我们设 $ dp[i][j][0/1/2] $ 分别表示,从上面走到 $ ( i , j ) $ ,从左边走到 $ ( i , j ) $ ,从下面走到 $ ( i , j ) $ 的最大值。
那么我们有转移方程:
$dp[i][[j][1] = max(dp[i][j-1][0],dp[i][j-1][1],dp[i][j-1][2]) + a[i][j] $
$dp[i][[j][0] = max(dp[i-1][j][0],dp[i-1][j][1]) + a[i][j] $
$dp[i][[j][2] = max(dp[i+1][j][2],dp[i+1][j][1]) + a[i][j] $

之所以 \(dp[i][j][0]\) 不从 \(dp[i-1][j][2]\) 转以来,是因为 \(dp[i-1][j][2]\) 取决于 \(dp[i][j][0/1/2]\) 中的最大值,不满足拓扑序。(或者说你从(i,j)走到(i-1,j)又走了回来,就算重复了)

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cctype>
#define INF 0x3f3f3f3f
#define MAX 0x7ffffffffffffff
#define del(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
template<typename T>
inline void read(T&x)
{
    x=0;T k=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=k;
}
const int maxn=105;
int dp[maxn][maxn][3];
int a[maxn][maxn];
int n,m;

int main()
{
	int t;
	read(t);
	for(int k=1;k<=t;k++){
		read(n),read(m);
		del(a,0);del(dp,-INF);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
			read(a[i][j]);

		dp[1][1][0]=dp[1][1][1]=dp[1][1][2]=a[1][1];
		for(int i=2;i<=n;i++) dp[i][1][0]=dp[i-1][1][0]+a[i][1];
		
		for(int j=2;j<=m;j++){
			
			for(int i=1;i<=n;i++)
			dp[i][j][1]=max(dp[i][j-1][0],max(dp[i][j-1][1],dp[i][j-1][2]))+a[i][j];
			// 下面两个要用到dp[i][j][1] 所以先处理dp[i][j][1] 
			for(int i=2;i<=n;i++)
			dp[i][j][0]=max(dp[i-1][j][1],dp[i-1][j][0])+a[i][j];
			for(int i=n-1;i>=1;i--)
			dp[i][j][2]=max(dp[i+1][j][1],dp[i+1][j][2])+a[i][j];
		}
		printf("Case #%d:\n",k);
		printf("%d\n",max(dp[1][m][0],max(dp[1][m][1],dp[1][m][2])));
	}
	return 0;
}
posted @ 2018-08-28 19:40  Mr_asd  阅读(81)  评论(0编辑  收藏  举报