1. 程式人生 > 其它 >[Acwing藍橋杯DP] 1212. 地宮取寶

[Acwing藍橋杯DP] 1212. 地宮取寶

題目:1212. 地宮取寶 - AcWing題庫

大意描述:有一個 n * m 的矩陣,從左上角到右下角走 ,每經過一個點 ,如果當前位置的寶物價值 大於手裡的最大寶物價值 可以選擇拿或者不拿

求 當走到右下角的時候 手中的寶物恰好為 k 件的 總方案數量 。

資料範圍: 1<=n,m<=50

                  1<=k<=12

                  0<=c<=12  // c表示的是每個位置的寶物的價值大小

 

題目分析:

看到這個題 有很多的約束條件 基本上是融合了2. 01揹包問題 - AcWing題庫 1015. 摘花生 - AcWing題庫

這兩個題

考慮從左上到右下 如果到一個點 如果該點的值 大於手裡最大值(一定大於手裡的任意一個價值)記錄一下手裡的最大值

本題還有個限制條件,就是到底右下角的時候,手中的寶物件數是k,所以也要記錄一下手裡有多少個寶物

那麼我們用閆氏DP分析法來分析一下

 

(DP分析自:www.acwing.com/solution/content/7116/)偷個懶QAQ!

這個題的難點在於:狀態計算部分,聯想到01揹包問題,對於每個物品,都有取或不取兩種選擇,而不取是肯定可以的,要取的話,要滿足揹包能放下這個條件

初始化比較簡單 就是 初始化剛開始的起點

檢視程式碼

f[1][1][1][g[1][1]]=1;//這是剛開始起點取的情況
f[1][1][0][0]=1;//這是剛開始起點不取的情況

我們可以注意到 起點不取這個物品的時候 初始化該點的最大價值是0 這裡是用了個小技巧 用0代表什麼都沒有的初始狀態 

所以我們要將所有的物品價值遞增  範圍就變成了1~13 ,這就需要在剛開始讀取價值時候 將價值加1 。這樣的化,如果後面的物品價值是0時候也能取

因為我們記錄的是方案數,只關心各個物品之間的大小關係,具體數值不影響答案,但是這樣的做法可以把0作為一個特殊邊界來處理。

(當然也可以賦-1,不同的理解)

那麼這道題基本上就解決了 

程式碼:

檢視程式碼

#include <bits/stdc++.h>

using namespace std;

const int N=55,M=13,MOD=1e9+7;

int f[N][N][M][M+1];
int n,m,k;
int g[N][N];

int main()
{
    cin>>n>>m>>k;
    
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>g[i][j];
            g[i][j]++;
        }
    }
    
    f[1][1][1][g[1][1]]=1;
    f[1][1][0][0]=1;
    
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
           if(i==1&&j==1)continue;
           for(int u=0;u<=k;u++)
           {
               for(int v=0;v<=M;v++)
               {
                   int &val=f[i][j][u][v];
                   val=(val+f[i-1][j][u][v])%MOD;
                   val=(val+f[i][j-1][u][v])%MOD;
                   if(u>0&&v==g[i][j])
                   {
                       for(int c=0;c<v;c++)
                       {
                           val=(val+f[i-1][j][u-1][c])%MOD;
                           val=(val+f[i][j-1][u-1][c])%MOD;
                       }
                   }
               }
           }
        }
    }
    
    int res=0;
    
    for(int i=0;i<=M;i++)
    {
        res=(res+f[n][m][k][i])%MOD;
    }
    
    cout<<res<<endl;
    
    return 0;
}