CH5102 NCSTOJ1444 传纸条 —— 线性DP降维

Description

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

数据规模约定:
30%的数据满足:1<=m,n<=10
100%的数据满足:1<=m,n<=50

Input

第一行有2个用空格隔开的整数n和m,表示有n行m列(1<=n,m<=50)。
接下来的n行是一个n*m的矩阵,每行的n个整数之间用空格隔开。

Output

一个整数,表示答案。

Sample Input

3 3
0 3 9
2 8 5
5 7 0

Sample Output

34

状态:路径长度/当前走过的步数。
记当前的步数为i,当前的两个坐标分别为x1,y1、x2,y2。我们可以只用3个变量i,x1,x2,F[i,x1,x2] 代表当前状态(y1 = i + 2 - x1,y2 = i + 2 - x2)。
起始状态:F[0,1,1] = A[1,1]
目标状态:F[N+M-2,N,N] = A[N,N]

#include 
#include 
#include 
#define maxn 55
using namespace std;
int f[maxn<<1][maxn][maxn];
int a[maxn][maxn];
int n,m;

int max_ele(int a,int b,int c,int d){
    if (b>a)
        a = b;
    if (c>a)
        a = c;
    if (d>a)
        a = d;
    return a;
}

int main(){
    cin >> n >> m;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            cin >> a[i][j];
    for (int k=1;k<=n+m-1;k++)
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++){
                if (k-i+1<1 || k-j+1<1) 
                    continue;
                 f[k][i][j] = max_ele(f[k-1][i][j],f[k-1][i-1][j-1],f[k-1][i][j-1],f[k-1][i-1][j]) + a[i][k-i+1] + a[j][k-j+1];
                if (i==j) 
                    f[k][i][j]-=a[i][k-i+1];
            }

    cout << f[n+m-1][n][n] << endl;
    return 0;
}

int n,m;
int A[maxn][maxn];
int F[maxn<<1][maxn][maxn];
int max3(int a, int b, int c, int d){
	if(b > a) a = b;
	if(c > a) a = c;
	if(d > a) a = d;
	return a;
}
int main(){
	cin>>n>>m;
	_rep(i,1,n)
	_rep(j,1,m)
	scanf("%d",&A[i][j]);
	_rep(i,1,n+m-1)
	_rep(x1,1,min(n-1,i))
	_rep(x2,1,min(n-1,i)){
		int y1 = i+2-x1, y2 = i+2-x2;
		F[i][x1][x2] = max3(F[i-1][x1][x2],F[i-1][x1-1][x2-1],F[i-1][x1][x2-1],F[i-1][x1-1][x2])+A[x1][y1]+A[x2][y2];
		if(x1==x2) F[i][x1][x2] -= A[x1][x1];
	}
	cout<<F[n+m-2][n][n]<<endl;
	return 0;
}


#include
#include
using namespace std;
int f[299][101][101],a[101][101],n,m,y_1,y_2;
int main() {
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            scanf("%d",&a[i][j]);
    f[0][1][1]=a[1][1];
    for (int i=0;i<=n+m-2;i++) {
        for (int x_1=1;x_1<=n;x_1++)
            for (int x_2=1;x_2<=n;x_2++) {
                y_1=i+2-x_1;
                y_2=i+2-x_2;
                if (x_1==x_2) f[i+1][x_1][x_2]=max(f[i+1][x_1][x_2],f[i][x_1][x_2]+a[x_1][y_1+1]);
                else f[i+1][x_1][x_2]=max(f[i+1][x_1][x_2],f[i][x_1][x_2]+a[x_1][y_1+1]+a[x_2][y_2+1]);//两个都往右走
                if (x_1+1==x_2) f[i+1][x_1+1][x_2]=max(f[i+1][x_1+1][x_2],f[i][x_1][x_2]+a[x_1+1][y_1]);
                else f[i+1][x_1+1][x_2]=max(f[i+1][x_1+1][x_2],f[i][x_1][x_2]+a[x_1+1][y_1]+a[x_2][y_2+1]);//一个往下走,一个往右走
                if (x_1==x_2+1) f[i+1][x_1][x_2+1]=max(f[i+1][x_1][x_2+1],f[i][x_1][x_2]+a[x_2+1][y_2]);
                else f[i+1][x_1][x_2+1]=max(f[i+1][x_1][x_2+1],f[i][x_1][x_2]+a[x_2+1][y_2]+a[x_1][y_1+1]);//一个往右走,一个往下走
                if (x_1+1==x_2+1) f[i+1][x_1+1][x_2+1]=max(f[i+1][x_1+1][x_2+1],f[i][x_1][x_2]+a[x_1+1][y_1]);
                else f[i+1][x_1+1][x_2+1]=max(f[i+1][x_1+1][x_2+1],f[i][x_1][x_2]+a[x_1+1][y_1]+a[x_2+1][y_2]);//都往右走
            }
    }
    printf("%d",f[n+m-2][n][n]);
}

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