题目:
一个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次。
分析:
dp[x1][y1][x2][y2]表示2条并行的路到达(x1,y1),(x2,y2)获得的最大值
如果(x1,y1) =/= (x2,y2)
dp[x1][y1][x2][y2] = dp[x1'][y1'][x2'][y2'] + val[x1][y1] + val[x2][y2]
否则
dp[x1][y1][x2][y2] = dp[x1'][y1'][x2'][y2'] + val[x1][y1]
观察知道x1+y1 = x2+y2
所以就可以把4维变成了3维。
dp[steps][x1][x2] = dp[steps-1][x1'][x2'] + val[x1][y1] + val[x2][y2]
代码:
#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;
int a[210][210];
int dp[420][210][210];
int m,n;
bool inRange(int x,int y) {
if(0 <= x && x < n && 0 <= y && y < m) {
return true;
}
return false;
}
int dir[2][2] = {-1,0,0,-1};
int main(){
freopen("in.txt","r",stdin);
scanf("%d%d",&m,&n);
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
scanf("%d",&a[i][j]);
}
}
memset(dp,0,sizeof(dp));
dp[0][0][0] = a[0][0];
for(int tot=1;tot<n+m-1;tot++) {
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
for(int d1=0;d1<2;d1++) {
for(int d2=0;d2<2;d2++) {
int x1 = i + dir[d1][0];
int y1 = tot - 1 - x1;
int x2 = j + dir[d2][0];
int y2 = tot -1 - x2;
if(!inRange(x1,y1) || !inRange(x2,y2)) {
continue;
}
if(i != j)
dp[tot][i][j] = max(dp[tot][i][j],dp[tot-1][x1][x2] + a[i][tot-i] + a[j][tot-j]);
else
dp[tot][i][j] = max(dp[tot][i][j],dp[tot-1][x1][x2] + a[i][tot-i]);
}
}
}
}
}
printf("%d\n",dp[n+m-2][n-1][n-1]);
}