【0x50 动态规划】传纸条【线性DP】

题意:

给定一个 N ∗ M N*M NM 的矩阵 A A A,每个格子中有一个整数。现在需要找到两条从左上角 ( 1 , 1 ) (1,1) (1,1) 到右下角 ( N , M ) (N,M) (N,M) 的路径,路径上的每一步只能向右或向下走。路径经过的格子中的数会被取走。两条路径不能经过同一个格子。求取得的数之和最大是多少。 N , M ≤ 50 。 N,M\leq50。 N,M50


思路:

D P DP DP 问题,首先需要列一下状态。对于此题,有一个很直接的想法就是 D P [ x 1 ] [ y 1 ] [ x 2 ] [ y 2 ] DP[x1][y1][x2][y2] DP[x1][y1][x2][y2] 表示第一条路径走到 ( x 1 , y 1 ) (x1,y1) (x1,y1),第二条路径走到 ( x 2 , y 2 ) (x2,y2) (x2,y2) 所能获得的最大值。然后再用这个状态去更新别的状态。

对于这题来说,由于数据范围比较小,因此到这里也就可以结束了。但是如果有意卡空间的话,我们就需要进一步优化了。观察当前的 D P DP DP 状态,每一维是否达到了线性无关。我们可以发现两条路径在更新时,应该保持长度一致。因此我们可以发现 x 1 + y 1 = x 2 + y 2 x1+y1=x2+y2 x1+y1=x2+y2,由此可以发现当前状态并没有达到线性无关,因此我们可以令 l e n = x 1 + y 1 = x 2 + y 2 len = x1+y1 = x2+y2 len=x1+y1=x2+y2,状态就变成了 D P [ l e n ] [ x 1 ] [ x 2 ] DP[len][x1][x2] DP[len][x1][x2],空间成功压缩到了三维,即可完成优化。


代码:

#include 
#include 
#include 
#include 
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
typedef long long ll;
typedef double db;
const db EPS = 1e-9;
using namespace std;
const int N = 50+10;

int n,m,c[N][N];
int dp[N][N][N][N];

bool cmp(int xx, int yy){
	if(xx < 1 || xx > n || yy < 1 || yy > m) return false;
	return true;
}

void solve(int xx1, int yy1, int xx2, int yy2, int cc){
	if(xx1 == n && yy1 == m && xx2 == n && yy2 == m)
		dp[xx1][yy1][xx2][yy2] = max(cc+c[xx1][yy1]+c[xx2][yy2],dp[xx1][yy1][xx2][yy2]);
	else if(cmp(xx1,yy1) && cmp(xx2,yy2) && !(xx1 == xx2 && yy1 == yy2))
		dp[xx1][yy1][xx2][yy2] = max(cc+c[xx1][yy1]+c[xx2][yy2],dp[xx1][yy1][xx2][yy2]);
}

int main()
{
	scanf("%d%d",&n,&m);
	rep(i,1,n) 
		rep(j,1,m) scanf("%d",&c[i][j]);
	rep(x1,1,n)
		rep(y1,1,m)
			rep(x2,1,n)
				rep(y2,1,m){
					if(x1 == x2 && y1 == y2 && !(x1 == 1 && y1 == 1 && x2 == 1 && y2 == 1) && x1+y1 != x2+y2) continue;
					solve(x1+1,y1,x2+1,y2,dp[x1][y1][x2][y2]);
					solve(x1,y1+1,x2,y2+1,dp[x1][y1][x2][y2]);
					solve(x1+1,y1,x2,y2+1,dp[x1][y1][x2][y2]);
					solve(x1,y1+1,x2+1,y2,dp[x1][y1][x2][y2]);
				}
	printf("%d\n",dp[n][m][n][m]);
	return 0;
}

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