1. 程式人生 > 其它 >演算法:地宮取寶(dp,動態規劃)

演算法:地宮取寶(dp,動態規劃)

技術標籤:演算法演算法動態規劃c++dp地宮取寶

思路

首先給定了一個數n×m地圖,每個格子上都有價值不同的物品,每次從左上角出發,然後只能向右或者向下走。每次走到新的格子上,如果當前格子上的價值大於手中全部物品的價值就可以拿走(也可以不拿)。問拿k個物品的方案數?
本題用dp的思路來解題,首先用兩維表示橫座標和縱座標。然後用一維來表示當前手上的物品數量。用一維表示當前手中的最大值。

  1. 當前格子是由左邊格子過來的
    1.1 不取當前格子的物品
    1.2 取當前格子的物品
    1.2.1 (需要滿足條件當前物品的價值為手中全部價值最大的)那麼當前格子的情況就是所有價值從0到當前格子價值-1。
  2. 當前格子是由上邊格子過來的
    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; }

原題連結