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




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章