51nod1409 贪吃蛇

48 篇文章 0 订阅

Jeff喜欢玩,贪吃蛇游戏。玩了很多次之后,他对里面的规则感到厌烦。

为了使得游戏更加有趣,他制定了一些新的规则:

1.    地图是由n*m个格子组成的(1 <= n, m <= 1000),n行,m列。

2.    每个格子有一个值vi (-1 ≤ vi≤ 99999),如果vi是-1,那么这个格子不能走,也不能穿过这个格子,如果不是-1,蛇经过这个点之后会获得vi的分数

3.    蛇可以从最左边的任意一个格子出发,他的目的是到达最右侧的某个格子中。

4.    在行走的过程中,蛇只能向上,向下,向右行走,即,当前在第x行,y列时(x,y),只能走到(x+1,y),(x-1,y),(x,y+1),每个格子最多只能经过一次。

其它情况说明:

a.蛇到达最右侧之后还是可以上下走动的。

b.如果蛇在最上面的格子时,他还可以往上面走,走上去之后就被(传送门,teleport)传送到了最下面的格子,并且之前的积分清0。在最下面的格子如果想往下走时,则会被传送到最上面的格子中,积分同样清0。

创建好这个游戏之后, Jeff在想怎么样才能获得最高的分数呢?请你写一个程序帮助他。

 

样例图解。

样例1

样例2

这儿用了teleport,到了2之后往下走到4。
Input
第一行有两个整数n,m,以一个空格分开。(1 <= n, m <= 1000)
接下来n行给出格子的信息。每一行包括m个整数vi, (-1 ≤ vi ≤ 99999),vi=-1时表示这个格子不能走。
Output
对于每一组数据,输出最高能获得的分数。如果蛇无法到达最右侧,输出-1。
Input示例
4 4
-1 4 5 1
2 -1 2 4
3 3 -1 3
4 2 1 2
4 4
-1 4 5 1
2 -1 2 4
3 3 -1 -1
4 2 1 2
Output示例
23
16

题解:orz神奇dp。具体明天再研究。


代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;

LL read(){
	LL x = 0, k = 1; char ch = getchar();
	while (ch < '0' || '9' < ch){
		if (ch == '-') k = -1;
		ch = getchar();
	}
	while ('0' <= ch && ch <= '9'){
		x = x*10 + ch-'0';
		ch = getchar();
	}
	return x*k;
}

const int maxn = 1005;
LL f[maxn][maxn], pf[maxn];
LL g[maxn][maxn], pg[maxn];
LL h[maxn][maxn];
LL v[maxn][maxn];
int n, m; LL ans;

int main(){
	while (~scanf("%d%d", &n, &m)){
		for (int i=1; i<=n; i++)
			for (int j=1; j<=m; j++)
				v[i][j] = read();
		for (int j=1; j<=m; j++){
			f[0][j] = g[n+1][j] = -1e18;
			for (int i=1; i<=n; i++)
				if (v[i][j] == -1) f[i][j] = -1e18;
				else if (h[i][j-1] >= f[i-1][j]) { f[i][j] = h[i][j-1] + v[i][j]; pf[i] = i; }
				else { f[i][j] = f[i-1][j] + v[i][j]; pf[i] = pf[i-1]; }
			for (int i=n; i>=1; i--)
				if (v[i][j] == -1) g[i][j] = -1e18;
				else if (h[i][j-1] >= g[i+1][j]) { g[i][j] = h[i][j-1] + v[i][j]; pg[i] = i; }
				else { g[i][j] = g[i+1][j] + v[i][j]; pg[i] = pg[i+1]; }
				
			if (g[n][j] >= 0) f[0][j] = 0;
			if (f[1][j] >= 0) g[n+1][j] = 0;
			for (int i=1; i<=pf[n]-1; i++)
				if (v[i][j] >= 0) f[i][j] = max(f[i][j], f[i-1][j]+v[i][j]);
			for (int i=n; i>=pg[1]+1; i--)
				if (v[i][j] >= 0) g[i][j] = max(g[i][j], g[i+1][j]+v[i][j]);
			for (int i=1; i<=n; i++)
				h[i][j] = max(f[i][j], g[i][j]);
		}
		ans = -1;
		for (int i=1; i<=n; i++)
			ans = max(ans, h[i][m]);
		printf("%lld\n", ans);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值