地宫取宝 (第五届蓝桥杯省赛C++A/B组)

时间:2022-07-28
本文章向大家介绍地宫取宝 (第五届蓝桥杯省赛C++A/B组),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题意描述

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

思路

这是一道动态规划的题目。我们可以用yxc的集合方法来分析动态规划。可以用dp[i][j][k][l]来表示,从起点到(i,j)点时,取得物品的数量为k,且最后一件取得的物品价值为l的方案数量,通过分析,我们可以发现,走到最后一步的方案数等于最后一步是从上走下来的方案数和最后一步是从左走过来的方案数相加,而最后一步又有取和不取两种情况,如果不取最后一件的话,那么状态方程很容易表示出来;如果取最后一件,则会比较复杂。根据题意,我们每次所取的最后一件一定是最大的,所以我们一定会有一个限定条件,即W==g[i][j],如果满足这个条件,那么就再进行一次循环,将方案数相加即可。关于细节问题,由于我们要选的是方案数,所以与物品价值大小无关。如果选第一件物品,则有初值dp[1][1][1][g[1][1]]=1。如果不选,则有dp[1][1][0][0]=1。

AC代码

#include<iostream>
using namespace std;
const int N=55;
const int MOD=1e9+7;
int dp[N][N][13][14];
int g[N][N];
int n,m,k;
int main(){
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>g[i][j];
            g[i][j]++;
        }
    }
    dp[1][1][1][g[1][1]]=1;
    dp[1][1][0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            for(int u=0;u<=k;u++){
                for(int v=0;v<=13;v++){
                    dp[i][j][u][v]=(dp[i][j][u][v]+dp[i-1][j][u][v])%MOD;
                    dp[i][j][u][v]=(dp[i][j][u][v]+dp[i][j-1][u][v])%MOD;
                    if(u>0&&v==g[i][j]){
                        for(int c=0;c<v;c++){
                            dp[i][j][u][v]=(dp[i][j][u][v]+dp[i-1][j][u-1][c])%MOD;
                            dp[i][j][u][v]=(dp[i][j][u][v]+dp[i][j-1][u-1][c])%MOD;
                        }
                    }
                }
            }
        }
    }
    int res=0;
    for(int i=0;i<=13;i++) res=(res+dp[n][m][k][i])%MOD;
    cout<<res<<endl;
    return 0;
}