74 地宫取宝
作者: Turbo时间限制: 1S章节: 动态规划
问题描述 :
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
代码:
/*
T74 地宫寻宝
涉及到动态规划,深度优先搜索,四维数组,取余相关数学原理
*/
#include<stdio.h>
#include<string.h>
#define MAX_SIZE 51
int n, m, k;
int map[MAX_SIZE][MAX_SIZE];// 宝物地图
int dp[MAX_SIZE][MAX_SIZE][15][15];
int dfs(int x, int y, int sum, int max);
int main() {
int i = 0, j = 0;
scanf("%d%d%d", &n, &m, &k);
for (i = 1; i <= n; i++) {
for (j = 1; j <= m; j++) {
scanf("%d", &map[i][j]);
}
}
memset(dp, -1, sizeof(dp));// 初始化
printf("%d\n", dfs(1, 1, 0, -1));
return 0;
}
// 求方案的总数
// x y sum max分别表示坐标(x, y),当前宝物数量,当前宝物最大价值
int dfs(int x, int y, int sum, int max) {
int plans = 0;// 从当前坐标到出口的方案总数
if (dp[x][y][sum][max + 1] != -1) {// 当前坐标已经计算过,则直接返回结果
return dp[x][y][sum][max + 1];
}
if (x == n && y == m) {// 地宫出口,也即递归出口
if (map[x][y] > max) {// 宝物价值大,可拿
if (sum == k || sum == k - 1) {// 宝物拿够了或者只差一件,则方案可行
plans++;
}
}
else if (sum == k) {
plans++;
}
return dp[x][y][sum][max + 1] = plans;// 这里sum不变,因为求的是(x,y)点的方案
}
// 当前点不是出口,则有两种情况,向右走或者向下走(如果能走的话)
// 而从当前点到出口的方案总数就是向右走和向下走两个方向的方案总数之和
if (x + 1 <= n) {// 向右走
// 决定了向右走,那么要看能不能拿当前点的宝物
if (map[x][y] > max) {
if (sum < k) {// 宝物不够,拿
plans += dfs(x + 1, y, sum + 1, map[x][y]);
plans %= 1000000007;
}
}
plans += dfs(x + 1, y, sum, max);
plans %= 1000000007;
}
if (y + 1 <= m) {// 向下走
if (map[x][y] > max) {
if (sum < k) {
plans += dfs(x, y + 1, sum + 1, map[x][y]);
plans %= 1000000007;
}
}
plans += dfs(x, y + 1, sum, max);
plans %= 1000000007;
}
dp[x][y][sum][max + 1] = plans;
return dp[x][y][sum][max + 1];
}
这竞赛题是真滴难……
参考了一位大佬