1084 矩阵取数问题 V2
基准时间限制:2 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 收藏 关注
一个M*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,先从左上走到右下,再从右下走到左上。第1遍时只能向下和向右走,第2遍时只能向上和向左走。两次如果经过同一个格子,则该格子的奖励只计算一次,求能够获得的最大价值。
例如:3 * 3的方格。
1 3 3
2 1 3
2 2 1
能够获得的最大价值为:17。1 -> 3 -> 3 -> 3 -> 1 -> 2 -> 2 -> 2 -> 1。其中起点和终点的奖励只计算1次。
Input
第1行:2个数M N,中间用空格分隔,为矩阵的大小。(2 <= M, N <= 200)
第2 - N + 1行:每行M个数,中间用空格隔开,对应格子中奖励的价值。(1 <= A[i,j] <= 10000)
Output
输出能够获得的最大价值。
Input示例
3 3
1 3 3
2 1 3
2 2 1
Output示例
17
这题如果直接上去想正着走一边,反着走一边,状态时很难想到的,学长教导我,要先观察题目的性质,正着走过去,再走回来,不就等于找两条从左上角到右下角的路么,并且中间走过相同的部分只算一次,然后要求最大,可以想到状态
dp[x1][y1][x2][y2]
,记为一条路走到x1,y1,另外条路走到x2,y2,这会最大的值是多少。
n,m的范围是200,所以四维并开不下,我们可以用路径长度step,代替掉y1,y2,因为知道了路径长度和x的位置,就能算出y的位置了。
这样转移就很简单了,两个点分别转移到边上的两个点即可,然后dp数组开200 * 200 * 400的有点吃紧,会MLE,所以可以滚动数组,把step这一维滚动掉,在外围先枚举step,然后枚举x1,x2
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")
using namespace std;
#define MAX 205
#define MAXN 6005
#define maxnode 15
#define sigma_size 30
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lrt rt<<1
#define rrt rt<<1|1
#define middle int m=(r+l)>>1
#define LL long long
#define ull unsigned long long
#define mem(x,v) memset(x,v,sizeof(x))
#define lowbit(x) (x&-x)
#define pii pair<int,int>
#define bits(a) __builtin_popcount(a)
#define mk make_pair
#define limit 10000
//const int prime = 999983;
const int INF = 0x3f3f3f3f;
const LL INFF = 0x3f3f;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-8;
const LL mod = 1e9+7;
const ull mx = 133333331;
/*****************************************************/
inline void RI(int &x) {
char c;
while((c=getchar())<'0' || c>'9');
x=c-'0';
while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/
int a[MAX][MAX];
int dp[MAX][MAX][2];
int main(){
//freopen("in.txt","r",stdin);
int m,n;
cin>>m>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
}
}
mem(dp,0);
int cur=0;
for(int st=2;st<=n+m;st++){
cur^=1;
for(int x1=max(1,st-m);x1<=n;x1++){
for(int x2=max(1,st-m);x2<=n;x2++){
int y1=st-x1;
int y2=st-x2;
if(x1==x2){
dp[x1][x2][cur]=max(max(dp[x1][x2][cur^1],dp[x1-1][x2-1][cur^1]),max(dp[x1-1][x2][cur^1],dp[x1][x2-1][cur^1]))+a[x1][y1];
}
else{
dp[x1][x2][cur]=max(max(dp[x1][x2][cur^1],dp[x1-1][x2-1][cur^1]),max(dp[x1-1][x2][cur^1],dp[x1][x2-1][cur^1]))+a[x1][y1]+a[x2][y2];
}
}
}
}
cout<<dp[n][n][cur]<<endl;
return 0;
}