P1004 [NOIP2000 提高组] 方格取数 题解(四维dp)

题目链接

题目大意

给你一个n*n的方格图(n<=9),每个格子有权值

某人从图的左上角的 A 点出发,可以向下行走,也可以向右走,直到到达右下角的 B 点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字 0)。
此人从 A 点到 B 点共走两次,试找出 2 条这样的路径,使得取得的数之和为最大。

题目思路

如果只走一次很好,直接二维dp

而走两次则可以想象为四维dp,用(f[i][j][k][l])表示第一个人走到(i,j),第二个人走到(k,l)的最优解

注意(i,j)和(k,l)相同特判即可

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=10+5,mod=1e9+7;
int dp[maxn][maxn][maxn][maxn];
int a[maxn][maxn];
int n;
int main(){
    scanf("%d",&n);
    while(1){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        if(u+v+w==0) break;
        a[u][v]=w;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            for(int k=1;k<=n;k++){
                for(int l=1;l<=n;l++){
                    dp[i][j][k][l]=max({dp[i-1][j][k-1][l],dp[i-1][j][k][l-1],dp[i][j-1][k-1][l],dp[i][j-1][k][l-1]});
                    if(i==k&&j==l){
                        dp[i][j][k][l]+=a[i][j];
                    }else{
                        dp[i][j][k][l]+=a[i][j]+a[k][l];
                    }
                }
            }
        }
    }
    printf("%d
",dp[n][n][n][n]);
    return 0;
}

还有一个相似的题目

题目链接

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long  ll;
const int maxn=50+5,mod=1e9+7,inf=0x3f3f3f3f;
int n,m;
int a[maxn][maxn];
int dp[maxn][maxn][maxn][maxn];
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]);
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            for(int k=1;k<=n;k++){
                for(int l=1;l<=m;l++){
                    if(i==k&&j==l&&(!(i==n&&j==m))){
                        dp[i][j][k][l]=-inf;
                    }else{
                        dp[i][j][k][l]=max({dp[i-1][j][k-1][l],dp[i][j-1][k-1][l],dp[i-1][j][k][l-1],dp[i][j-1][k][l-1]})+a[i][j]+a[k][l];
                    }
                }
            }
        }
    }
    printf("%d
",dp[n][m][n][m]);
    return 0;
}