zoukankan      html  css  js  c++  java
  • [蓝桥]地宫取宝(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
    ", dp[0][0][0][0]);
    59     }
    60     return 0;
    61 }
  • 相关阅读:
    使用超酷的jQuery缩略图生成插件NailThumb制作漂亮的缩略图web应用
    极客Web前端开发资源大荟萃#015
    极客编程小挑战#29:实现手机上常见的某一功能的效果显示
    在线制作gif loading图
    极客标签二重大礼华丽登场 宅男宅女必备套装
    SVG矢量图形课程基础入门篇
    浏览器JS交互,点击查询
    11选5专家投注研究算法
    大龙VBox API参数插件
    利用DLL劫持内存补丁技术注入
  • 原文地址:https://www.cnblogs.com/kirai/p/5292162.html
Copyright © 2011-2022 走看看