题面
X 国王有一个地宫宝库。是 n×m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。
地宫的入口在左上角,出口在右下角。
小明被带到地宫的入口,国王要求他只能向右或向下行走。
走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。
当小明走到出口时,如果他手中的宝贝恰好是 k 件,则这些宝贝就可以送给小明。
请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这 k 件宝贝。
输入描述
输入一行 3 个整数,用空格分开:n,m,k (1≤n,m≤50,1≤k≤12)。
接下来有 n 行数据,每行有 m 个整数 代表这个格子上的宝物的价值。
输出描述
要求输出一个整数,表示正好取 k 个宝贝的行动方案数。该数字可能很大,输出它对 109+7 取模的结果。
输入样例
2 2 2
1 2
2 1
输出样例
2
题解
动态规划
0/1背包的变体,即选和不选问题。
-
状态表示:
f[i][j][x][y]
表示当前走到格子(i, j)
处,且手中有x
件物品同时这些物品的最大价值为y
的方案数量。 -
状态计算:
- 当前格子的物品不拿:则当前状态由前一个位置的方案数量之和,如下
- 当前格子的物品拿走:则当前格子的状态为
f[i][j][x][a[i][j]]
时,其计算结果等于
在运算时注意取模,最后计算完所有状态后,累加在终点 (m, n)
恰好取到 k
个物品的方案数即为答案。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 55, M = 15, MOD = 1e9 + 7;
int f[N][N][M][M];
int n, m, k;
int a[N][N];
int main() {
cin >> m >> n >> k;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
scanf("%d", &a[i][j]);
a[i][j]++;
}
}
f[1][1][0][0] = 1;
f[1][1][1][a[1][1]] = 1;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
for (int x = 0; x <= k; x++) {
for (int y = 0; y <= 13; y++) {
//不选
if (i > 1) f[i][j][x][y] = (f[i][j][x][y] + f[i - 1][j][x][y]) % MOD;
if (j > 1) f[i][j][x][y] = (f[i][j][x][y] + f[i][j - 1][x][y]) % MOD;
//选
if (x && y == a[i][j]) {
for (int z = 0; z < a[i][j]; z++) {
//上面来的
if (i > 1) f[i][j][x][y] = (f[i][j][x][y] + f[i - 1][j][x - 1][z]) % MOD;
//左边来的
if (j > 1) f[i][j][x][y] = (f[i][j][x][y] + f[i][j - 1][x - 1][z]) % MOD;
}
}
}
}
}
}
int ans = 0;
for (int i = 0; i <= 13; i++) ans = (ans + f[m][n][k][i]) % MOD;
cout << ans << endl;
return 0;
}
标题: | 2014年第五届蓝桥杯省赛-I. 地宫取宝 |
---|---|
链接: | https://www.fightingok.cn/detail/170 |
更新: | 2022-09-18 22:45:02 |
版权: | 本文采用 CC BY-NC-SA 3.0 CN 协议进行许可 |