设有 N×N 的方格图,我们在其中的某些方格中填入正整数,而其它的方格中则放入数字0。如下图所示:
acwing1027. 方格取数1

某人从图中的左上角 A 出发,可以向下行走,也可以向右行走,直到到达右下角的 B 点。

在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。

此人从 A 点到 B 点共走了两次,试找出两条这样的路径,使得取得的数字和为最大。
acwing1027. 方格取数

思路

用f[i1,j1,i2,j2]表示从起点(1,1)到达(i1,j1)和(i2,j2)两个点时的最大值,当两条路径重合时,必有i1+j1=i2+j2。此时令k=i1+j1=i2+j2,那么坐标就可以表示为三维: f[k,i1,i2],这是因为j1和j2可以用k-i1和k-i2表示出来。

状态转移方程:
每次这两个从(1,1)出发的点,可以向右和向下移动,那么f[i1,j1,i2,j2]=max(f[i1-1,j1,i2-1,j2],f[i1,j1-1,i2,j2-1],f[i1,j1-1,i2-1,j2],f[i1,j1-1,i2-1,j2])+w[i1,j1]+w[i2,j2]
若位于同一点,只需要加一次。

#include<iostream>
using namespace std;
const int N=15;
int n;
int w[N][N],f[2*N][N][N];

int main(){

    cin>>n;
    int a,b,c;
    while(cin>>a>>b>>c,a||b||c){
        w[a][b]=c;
    }
    for(int k=2;k<=n+n;k++){
        for(int i1=1;i1<=n;i1++){
            for(int i2=1;i2<=n;i2++){
                int j1=k-i1,j2=k-i2;
                if(j1>=1&&j1<=n&&j2>=1&&j2<=n){
                    int t=w[i1][j1];
                    if(i1!=i2)t+=w[i2][j2];//位于同一点只需要加一次
                    int &x=f[k][i1][i2];
                    x=max(x,f[k-1][i1-1][i2]+t);
                    x=max(x,f[k-1][i1-1][i2-1]+t);
                    x=max(x,f[k-1][i1][i2]+t);
                    x=max(x,f[k-1][i1][i2-1]+t);
                }
            }
        }
    }
    cout<<f[n+n][n][n];
    return 0;
}