Acwing 1027. 方格取數(四維dp)

傳送門

設有 N×N 的方格圖,我們在其中的某些方格中填入正整數,而其它的方格中則放入數字0。如下圖所示:

在這裏插入圖片描述

某人從圖中的左上角 A 出發,可以向下行走,也可以向右行走,直到到達右下角的 B 點。

在走過的路上,他可以取走方格中的數(取走後的方格中將變爲數字0)。

此人從 A 點到 B 點共走了兩次,試找出兩條這樣的路徑,使得取得的數字和爲最大。

輸入格式
第一行爲一個整數N,表示 N×N 的方格圖。

接下來的每行有三個整數,第一個爲行號數,第二個爲列號數,第三個爲在該行、該列上所放的數。

一行“0 0 0”表示結束。

輸出格式
輸出一個整數,表示兩條路徑上取得的最大的和。

數據範圍
N≤10
輸入樣例:
8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0
輸出樣例:
67

做法1:dfs第一次走的所有路徑,將走過的點標記一下,終點進行正常二維dp。

做法2:四維dp,dp[i][j][k][r] 表示有兩個人同時走,第一個人走到(i, j) 第二個人走到(k, r)的時候能獲得的最大價值。

兩個人都要從上邊或者左邊的格子轉移過來,那麼有四種不同的轉移方式,轉移方程是:dp[i][j][k][r] = max(dp[i-1][j][k][r], dp[i-1][j][k][r-1], dp[i][j-1][k-1][r], dp[i][j-1][k][r-1])+a[i][j]+a[k][r]
如果兩個人走到同一個點,a[i][j] 和 a[k][r]只能加一次,那麼減掉一個就好。

做法1 : dfs+dp 做法 :

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N = 15;
int a[N][N],vis[N][N],dp[N][N],ans,n;
void dfs(int x,int y,int sum)
{
    if(x>n||y>n) return;
    vis[x][y]=1;
    if(x==n&&y==n)
    {
        memset(dp,0,sizeof dp);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                dp[i][j]+=max(dp[i-1][j],dp[i][j-1]);
                if(!vis[i][j]) dp[i][j]+=a[i][j];
            }
        ans=max(ans,sum+dp[n][n]);
    }
    dfs(x+1,y,sum+a[x+1][y]);
    vis[x+1][y]=0;
    dfs(x,y+1,sum+a[x][y+1]);
    vis[x][y+1]=0;
}
int main()
{
    int x,y,z;
    cin>>n;
    while(cin>>x>>y>>z && (x||y||z))
        a[x][y]=z;
    dfs(1,1,a[1][1]);
    cout<<ans<<endl;
    return 0;
}


做法2: 四維dp做法

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N = 15;
int a[N][N],dp[N][N][N][N];
int main()
{
    int n,x,y,z;
    cin>>n;
    while(cin>>x>>y>>z && (x||y||z))  
        a[x][y]=z;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++)
                for(int r=1;r<=n;r++)
                {
                    int &v=dp[i][j][k][r];
                    v=max(v,dp[i-1][j][k-1][r]+a[i][j]+a[k][r]);
                    v=max(v,dp[i-1][j][k][r-1]+a[i][j]+a[k][r]);
                    v=max(v,dp[i][j-1][k-1][r]+a[i][j]+a[k][r]);
                    v=max(v,dp[i][j-1][k][r-1]+a[i][j]+a[k][r]);
                    if(i==k&&j==r) v-=a[i][j];
                }
    cout<<dp[n][n][n][n]<<endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章