地宫取宝

地宫取宝

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

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

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

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

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

请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这 k 件宝贝。

输入格式

第一行 3 个整数,n,m,k,含义见题目描述。

接下来 n 行,每行有 m 个整数 Ci 用来描述宝库矩阵每个格子的宝贝价值。

输出格式

输出一个整数,表示正好取 k 个宝贝的行动方案数。

该数字可能很大,输出它对 1000000007 取模的结果。

数据范围

1n,m50,
1k12,
0Ci12

输入样例1:

2 2 2
1 2
2 1

输出样例1:

2

输入样例2:

2 3 2
1 2 3
2 1 5

输出样例2:

14

 

解题思路

  可以发现这是一个求集合最大值的问题,可以用动态规划。题目的限制有,每次只能向下或向右走、一定要按照递增的顺序取物品、要恰好取k件物品。

  dp的维度可以根据这几个限制来确定。首先用2维来表示坐标。再用1维来表示取的最后一件物品的值,因为物品是按照递增的顺序取的,因此只需要知道最后取的物品大小就可以了。再开一维来表示取了多少件物品。所以dp的维度为4维,f(i,j,k,c)

  大概可以知道一共需要5重循环,前4重循环来枚举4个维度,还需要一个循环来进行状态转移计算。大概是一个50×50×12×13×(25)的计算量。

  AC代码如下:

复制代码
 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 const int N = 60, M = 15, mod = 1e9 + 7;
 6 
 7 int graph[N][N], f[N][N][M][M];
 8 
 9 int main() {
10     int n, m, num;
11     scanf("%d %d %d", &n, &m, &num);
12     for (int i = 1; i <= n; i++) {
13         for (int j = 1; j <= m; j++) {
14             scanf("%d", &graph[i][j]);
15             graph[i][j]++;      // c的取值范围变为1~13,因为0用来表示当k为0时取的最后一件物品的价值为0
16         }
17     }
18     
19     // 初始化,(1, 1)取一件物品,最后一件物品的价值就是graph[i][j]; (1, 1)不取物品,对应最小的数0
20     f[1][1][1][graph[1][1]] = f[1][1][0][0] = 1;
21     for (int i = 1; i <= n; i++) {
22         for (int j = 1; j <= m; j++) {
23             for (int k = 0; k <= num; k++) {
24                 for (int u = 0; u < M; u++) {
25                     f[i][j][k][u] = (f[i][j][k][u] + f[i - 1][j][k][u]) % mod;
26                     f[i][j][k][u] = (f[i][j][k][u] + f[i][j - 1][k][u]) % mod;
27                     if (u == graph[i][j] && k) {    // 因为时取得情况,要求k>0,且满足u==graph[i][j]
28                         for (int c = 0; c < u; c++) {
29                             f[i][j][k][u] = (f[i][j][k][u] + f[i - 1][j][k - 1][c]) % mod;
30                             f[i][j][k][u] = (f[i][j][k][u] + f[i][j - 1][k - 1][c]) % mod;
31                         }
32                     }
33                 }
34             }
35         }
36     }
37     
38     int ret = 0;
39     for (int i = 1; i < M; i++) {
40         ret = (ret + f[n][m][num][i]) % mod;
41     }
42     printf("%d", ret);
43     
44     return 0;
45 }
复制代码

 

参考资料

  AcWing 1212. 地宫取宝(蓝桥杯C++ AB组辅导课):https://www.acwing.com/video/638/

posted @   onlyblues  阅读(138)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示