演算法:地宮取寶(dp,動態規劃)
阿新 • • 發佈:2021-02-06
思路
首先給定了一個數n×m地圖,每個格子上都有價值不同的物品,每次從左上角出發,然後只能向右或者向下走。每次走到新的格子上,如果當前格子上的價值大於手中全部物品的價值就可以拿走(也可以不拿)。問拿k個物品的方案數?
本題用dp的思路來解題,首先用兩維表示橫座標和縱座標。然後用一維來表示當前手上的物品數量。用一維表示當前手中的最大值。
- 當前格子是由左邊格子過來的
1.1 不取當前格子的物品
1.2 取當前格子的物品
1.2.1 (需要滿足條件當前物品的價值為手中全部價值最大的)那麼當前格子的情況就是所有價值從0到當前格子價值-1。 - 當前格子是由上邊格子過來的
2.1 不取當前格子的物品
2.2 取當前格子的物品
2.2.1 (需要滿足條件當前物品的價值為手中全部價值最大的)那麼當前格子的情況就是所有價值從0到當前格子價值-1。
問題描述
X 國王有一個地宮寶庫,是 n×m 個格子的矩陣,每個格子放一件寶貝,每個寶貝貼著價值標籤。
地宮的入口在左上角,出口在右下角。
小明被帶到地宮的入口,國王要求他只能向右或向下行走。
走過某個格子時,如果那個格子中的寶貝價值比小明手中任意寶貝價值都大,小明就可以拿起它(當然,也可以不拿)。
當小明走到出口時,如果他手中的寶貝恰好是 k 件,則這些寶貝就可以送給小明。
請你幫小明算一算,在給定的局面下,他有多少種不同的行動方案能獲得這 k 件寶貝。
輸入格式
第一行 3 個整數,n,m,k,含義見題目描述。
接下來 n 行,每行有 m 個整數 Ci 用來描述寶庫矩陣每個格子的寶貝價值。
輸出格式
輸出一個整數,表示正好取 k 個寶貝的行動方案數。
該數字可能很大,輸出它對 1000000007 取模的結果。
資料範圍
1≤n,m≤50,
1≤k≤12,
0≤Ci≤12
輸入樣例1:
2 2 2
1 2
2 1
輸出樣例1:
2
輸入樣例2:
2 3 2
1 2 3
2 1 5
輸出樣例2:
14
程式碼
#include<iostream>
using namespace std;
const int N = 60;
int map[N][N];
int f[N][N][13][14];
const int MOD = 1000000007;
int main(){
int n, m, k;
cin >> n >> m >> k;
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j){
scanf("%d", &map[i][j]);
map[i][j]++;
}
}
f[1][1][0][0] = 1;
f[1][1][1][map[1][1]] = 1;
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j){
for(int v = 0; v <= k; ++v){
for(int c = 0; c <= 13; ++c){
// 不取當前格子的物品
f[i][j][v][c] = (f[i][j][v][c] + f[i-1][j][v][c]) % MOD;
f[i][j][v][c] = (f[i][j][v][c] + f[i][j-1][v][c]) % MOD;
if(v > 0 && c == map[i][j]){
// 取當前格子的物品
for(int l = 0; l < c; ++l){
f[i][j][v][c] = (f[i][j][v][c] + f[i-1][j][v-1][l]) % MOD;
f[i][j][v][c] = (f[i][j][v][c] + f[i][j-1][v-1][l]) % MOD;
}
}
}
}
}
}
int ans = 0;
for(int c = 1; c <= 13; ++c){
ans = (ans + f[n][m][k][c]) % MOD;
}
cout << ans << endl;
return 0;
}