[蓝桥]地宫取宝(dp, 记忆化搜索)

问题描述
  X 国王有一个地宫宝库。是 n x m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。

  地宫的入口在左上角,出口在右下角。

  小明被带到地宫的入口,国王要求他只能向右或向下行走。

  走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。

  当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明。

  请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝。
输入格式
  输入一行3个整数,用空格分开:n m k (1<=n,m<=50, 1<=k<=12)

  接下来有 n 行数据,每行有 m 个整数 Ci (0<=Ci<=12)代表这个格子上的宝物的价值
输出格式
  要求输出一个整数,表示正好取k个宝贝的行动方案数。该数字可能很大,输出它对 1000000007 取模的结果。
样例输入
2 2 2
1 2
2 1
样例输出
2
样例输入
2 3 2
1 2 3
2 1 5
样例输出
14

 

dp,记忆化搜索可以免除一些不必要的计算。记录当前坐标和当前宝物数量还有当前持有最大价值。每次更新前要判断下一步是否满足条件

状态转移方程:

dp(i, j, k, v) = max (

  dp(i+1, j, k, v) + dp(i, j+1, k, v) (G(i, j) <= v),

  dp(i+1, j, k+1, G(i, j)) + dp(i, j+1, k+1, G(i, j)) + dp(i+1, j, k, v) + dp(i, j+1, k, v) (G(i, j) > v)

)

代码如下:

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <iomanip>
 4 #include <cstring>
 5 #include <climits>
 6 #include <complex>
 7 #include <fstream>
 8 #include <cassert>
 9 #include <cstdio>
10 #include <bitset>
11 #include <vector>
12 #include <deque>
13 #include <queue>
14 #include <stack>
15 #include <ctime>
16 #include <set>
17 #include <map>
18 #include <cmath>
19 
20 using namespace std;
21 
22 typedef long long ll;
23 const ll maxn = 55;
24 const ll mod = 1000000007;
25 int n, m, kk;
26 ll G[maxn][maxn];
27 ll dp[maxn][maxn][15][15];
28 
29 ll dfs(ll i, ll j, ll k, ll v) {
30     if(dp[i][j][k][v+1] != -1) return dp[i][j][k][v+1];
31     if(i == n - 1 && j == m - 1) {
32         if(k == kk) return dp[n-1][m-1][k][v+1] = 1;
33         else if(k == kk - 1 && G[n-1][m-1] > v) return dp[n-1][m-1][k][v+1] = 1;
34         else return dp[n-1][m-1][k][v+1] = 0;
35     }
36     ll s = 0;
37     if(G[i][j] > v) {
38         if(i + 1 < n) s = ((s + dfs(i+1, j, k+1, G[i][j])) % mod + dfs(i+1, j, k, v) % mod) % mod;
39         if(j + 1 < m) s = ((s + dfs(i, j+1, k+1, G[i][j])) % mod + dfs(i, j+1, k, v) % mod) % mod;
40     }
41     else {
42         if(i + 1 < n) s = (s + dfs(i+1, j, k, v) % mod) % mod;
43         if(j + 1 < m) s = (s + dfs(i, j+1, k, v) % mod) % mod;
44     }
45     return dp[i][j][k][v+1] = s;
46 }
47 
48 int main() {
49     // freopen("in", "r", stdin);
50     while(~scanf("%d %d %d", &n, &m, &kk)) {
51         memset(dp, -1, sizeof(dp));
52         for(ll i = 0; i < n; i++) {
53             for(ll j = 0; j < m; j++) {
54                 scanf("%d", &G[i][j]);
55             }
56         }
57         dfs(0, 0, 0, -1);
58         printf("%I64d\n", dp[0][0][0][0]);
59     }
60     return 0;
61 }

 

posted @ 2016-03-18 15:03  Kirai  阅读(174)  评论(0编辑  收藏  举报