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即可。


<span style="font-size:14px;">#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
long n,m;
long s[8003][1004];
long f[8003][1004];

inline long max(long a,long b,long c)
{long h;
 h=(a>b)? a:b;
 h=(h>c)? h:c;
 return h;}

int main()
{cin>>n>>m;
 long 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;}</span>



posted on 2015-08-28 17:42  lcyzgdy  阅读(141)  评论(0编辑  收藏  举报

导航