蓝桥杯2014年第五届真题-地宫取宝
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 3 2
1 2 3
2 1 5
样例输出
14
解题思路:
以前都是用vis[ ][ ]数组判断该位置有没有被访问过,现在情况有所改动,除了位置,他还带着 “当前手中宝物价值的最大值:max” 以及 “当前手中宝物数:cnt”,所以开辟一个缓存数组cache[x][y][max][cnt]将四种状态都记录
( x , y ) | (x , y+1) |
---|---|
(x , y+1) | p |
比如说:(x,y)想要到达p点,是向右还是向左,是拾起(x,y)格子处的宝物还是不拾起,无论是怎么到达p点的,如果在p点发现dfs(i,j,max,cnt)中i,j,max,cnt,和缓存中的一样,那就是重复搜索了。可以采用动态规划(dp):动归数组、逐步生成或者记忆性递归,这里采用记忆性递归,因此开辟一个缓存数组。
#include<iostream>
#include<algorithm>
#include<cstring>
#define MOD 1000000007
using namespace std;
int n, m, k;
int maze[50][50];
long long ans;
long long cache[50][50][14][13];//缓存数组
long long dfs(int x, int y, int max, int cnt)//不再是void,而是返回long long 类型的方案数ans
{
//先查缓存,缓存里有,直接用
if (cache[x][y][max+1][cnt] != -1)//记忆化搜索,
此处为什么max+1,因为题目中宝物价值是:Ci (0< =Ci< =12),包含0,所以可能取到0,那我在main函数调用时初始化max只能是负数,否则如果起始点为0,我就不能拾起了,但数组下标又不能是负数,干脆直接化为max+1,max+1>=0说明拾起第一件宝物
return cache[x][y][max+1][cnt];
//如果越界或者当前手中宝物数大于k,退出
if (x == n || y == m || cnt > k)
return 0;
int cur = maze[x][y];//当前宝物价值
long long ans = 0;
//走到最后一格
if (x == n - 1 && y == m - 1)
{
//手中宝物数等于k 或者 手中宝物数比k少1,并且当前格子宝物价值大于手中宝物价值的最大值,可以捡起最后一个宝物,同样符合条件。因此方案数+1
if (cnt == k||(cnt==k-1&&cur>max))
{
ans++;
if (ans > MOD)//取模操作
ans = ans % MOD;
}
return ans;//返回方案数
}
//当前格子宝物价值大于手中宝物价值的最大值,并且拾起该宝物,将方案数叠加
if (cur > max)
{
ans += dfs(x, y + 1, cur, cnt + 1);//向右
ans += dfs(x + 1,y , cur, cnt + 1);//向下
}
//1. 当前当前格子宝物价值大于手中宝物价值的最大值,但不拾起
//2. 当前当前格子宝物价值小于手中宝物价值的最大值
ans += dfs(x, y + 1, max, cnt);//向右
ans += dfs(x + 1, y, max, cnt);//向下
//写入缓存
cache[x][y][max+1][cnt] = ans % MOD;
return cache[x][y][max+1][cnt];//返回方案数
}
int main()
{
cin >> n >> m >> k;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
cin >> maze[i][j];
memset(cache, -1, sizeof(cache));//初始化为-1
cout<<dfs(0, 0, -1, 0)<<endl;
return 0;
}