zoukankan      html  css  js  c++  java
  • 蓝桥杯-地宫取宝

    问题描述
      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+记忆化dfs。这题目类似于数字三角形问题。dp 的状态转移方程为

    这题目最难理解的地方可能就是递归的出口

    1、如果当前dp[i][j][k][v]之前就被访问过,直接返回值。

    2、如果到达出口,判断是否已经拥有了k件物品,如果有,则不取,方案为1;判断是否有k-1件物品且要取的物品价值是否比所有的都大,如果是,方案为1;否则返回0。

    AC代码:

     1 #include<iostream>
     2 #include<bits/stdc++.h>
     3 #define MOD 1000000007
     4 #define ll long long
     5 using namespace std;
     6 ll dp[60][60][105][20];
     7 ll mp[60][60];
     8 ll n,m,k;
     9 ll dfs(ll i,ll j,ll num,ll max_value){
    10     ll cnt=0;
    11     if(dp[i][j][num][max_value]!=-1){
    12         return dp[i][j][num][max_value]; //递归出口
    13     }
    14     if(i==n-1&&j==m-1){ //判断是否到达出口
    15         if(num==k||(num==k-1&&mp[i][j]>max_value)){
    16             dp[i][j][num][max_value]=1;
    17             return dp[i][j][num][max_value];
    18         }else{
    19             dp[i][j][num][max_value]=0;
    20             return dp[i][j][num][max_value];
    21         }
    22     }
    23     if(i<n-1){
    24         if(mp[i][j]>max_value){
    25             cnt=(cnt+dfs(i+1,j,num+1,mp[i][j]))%MOD;
    26         }
    27         cnt=(cnt+dfs(i+1,j,num,max_value))%MOD;
    28     }
    29     if(j<m-1){
    30         if(mp[i][j]>max_value){
    31             cnt=(cnt+dfs(i,j+1,num+1,mp[i][j]))%MOD;
    32         }
    33         cnt=(cnt+dfs(i,j+1,num,max_value))%MOD;
    34     }
    35     dp[i][j][num][max_value]=cnt%MOD;
    36     return dp[i][j][num][max_value];
    37 }
    38 int main(){
    39     memset(dp,-1,sizeof(dp));
    40     cin>>n>>m>>k;
    41     for(ll i=0;i<n;i++){
    42         for(ll j=0;j<m;j++){
    43             scanf("%d",&mp[i][j]);
    44             mp[i][j]++;  //防越界
    45         }
    46     }
    47     cout<<dfs(0,0,0,0)<<endl;
    48     return 0;
    49 }
  • 相关阅读:
    有关C#中List排序的总结
    配置jdk1.8.0_77
    New Day
    HDU 4288 Coder 线段树
    AOJ 169 找零钱 DP OR 母函数
    HDU 3954 Level up 线段树
    HDU 3016 Man Down 线段树+简单DP
    HDU 4027 Can you answer these queries? 线段树
    HDU 3333 Turing Tree 树状数组 离线查询
    POJ 2464 Brownie Points II 树状数组+扫描线
  • 原文地址:https://www.cnblogs.com/ISGuXing/p/8573427.html
Copyright © 2011-2022 走看看