tyvj p1264 艾泽拉斯的激流



描述

沿着卡利姆多北方边界延展的破碎的海岸,在世界大分裂之前曾经是暗夜精灵首都艾萨琳的一部分,艾萨拉。恶魔从这个世界被消除,这片土地被撕碎并被大海吞没,剩下的只有曾经雄伟城市的废墟。自那以后,这个岩石交错的岛屿、峭壁悬崖和珊瑚丛生的海洋成为许多传说来源。暗夜精灵们认为这是个被诅咒的地方,连经验最丰富的船长都从这里绕行。这里有巨大的水生物,可怕的暗礁,强大的激流与巨浪。然而传闻这里水下有着惊人的宝藏,吸引了一支矮人探险队前来。矮人们经过多日的探险,终于发现了在一个水域下面有着未知的宝藏。但是这个海域常常有着激流与巨浪,矮人们不可能把探险艇停下来甚至逆流而上。
这个海域可以被描述为一个W×L的矩形,分成个一个个单元格。每个单元格代表的海域下面可能是宝藏,也可能是一块可怕地礁石。从激流的上游开始,每过1秒探险艇就会被冲往下游的一个单位。在被冲往下游的过程中,矮人们可以控制方向,选择他的正前,左前边,或右前边的一个单位。矮人们决定从这个激流的最上游的任意一个单元格开始向下漂流,每经过一个单元格就可以取走这个单元格上的宝藏。但是千万不能碰到礁石,否则他的探险艇会支離破碎。请你安排一个计划,算出探险队最多一共能拿到多少宝藏。                    

输入格式

第1行,两个整数W,L。
接下来的L行,每行W个整数,以“从上游到下游,面朝水流方向从左向右”的顺序依次为每个单元格中的宝藏的数目,如果为-1则表示这个单元格是礁石。

输出格式

一个整数,表示得到的宝藏。                    

测试样例1

输入

3 5
5 1 3
-1 7 -1
5 1 10
4 -1 7
20 10 5

输出

41

备注

上游->下游1 2 3 4 5
1   5 -1 5 4 20
2   1 7 1 -1 10
3   3 -1 10 7 5

如上表,探险队从(1,1)开始,第1秒向右转一下,被冲到(2,2)。第2秒向左转一下,被冲到(3,1)。接下来第3秒正前行走,经过(4,1),(5,1),一共拿到5+7+5+4+20=41个单位的宝藏。
数据规模
1<=W<=1000
1<=L<=8000
所有涉及到的数字不会超过32位带符号整型的范围


根据题意,可以轻易想到用搜索或者动态规划来解决。考虑到数据规模,搜索应该使用记忆化搜索。这里介绍逆推动态规划算法。

考虑是从第一行任意位置出发,所以最终状态是max(f[1][1..w])。

由于只能向前、左前、右前移动,所以每一个点的状态由其下方、左下方、右下方转移过来,所以动态转移方程为:f[i][j]=max(f[i+1][j],f[i+1][j-1],f[i+1][j+1])+s[i][j],其中需要考虑边缘的状态。由于题目中说有障碍,所以将障碍点赋值为-maxlongint即可。

边缘直接赋值为0即可。


#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int n, m;
int s[8003][1004];
int f[8003][1004];

int main()
{
	cin >> n >> m;
	int i, j, k;
	memset(s, 128, sizeof(s));
	memset(f, -11, sizeof(f));
	for (i = 1; i <= m; i++)
	{
		for (j = 1; j <= n; j++)
		{
			cin >> s[i][j];
			if (s[i][j] == -1) s[i][j] = -0x77777777;
		}
	}
	for (i = 1; i <= n; i++)
	{
		f[m][i] = s[m][i];
	}
	for (i = (m - 1); i >= 1; i--)
	{
		for (j = 1; j <= n; j++)
		{
			f[i][j] = max({ f[i + 1][j], f[i + 1][j - 1], f[i + 1][j + 1] }) + s[i][j];
		}
	}
	j = 0;
	for (i = 1; i <= n; i++)
	{
		j = (j > f[1][i]) ? j : f[1][i];
	}
	cout << j << endl;
	return 0;
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值