dp-更难的矩阵取数问题

题目:    

一个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]);
}




你可能感兴趣的:(算法,动态规划)