问题 1436: [蓝桥杯][2014年第五届真题]地宫取宝
时间限制: 1Sec 内存限制: 128MB 提交: 1597 解决: 388
题目描述
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
思路:
数据很大,单纯的DFS肯定会超时,这里需要用到记忆化搜索。
有四个状态,当前坐标x,y,已经得到的最大值,已经拿到的宝贝个数。
每次有两种状态,当前坐标满足条件的话,拿这个地方的宝贝,或者不拿。
在这个过程中记录满足条件的走法个数。
注意:因为宝贝价值可能为0,我们将其初始值全部加1,因为我们初始化是最大值为0,遇到为0的宝贝就不能走了。
代码:
#include<iostream>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
#include<string.h>
#include<queue>
#include<stack>
#include<cstdio>
using namespace std;
const int maxn=50+6;
#define mod 1000000007
#define INF 0x3f3f3f
int n,m,k;
int w[maxn][maxn];
int state[60][60][20][20];
int dfs(int x,int y,int maxx,int num)
{
if(state[x][y][maxx][num]!=-1)return state[x][y][maxx][num];
if(x==n-1&&y==m-1)
{
return state[x][y][maxx][num]=(num==k||(num==k-1&&w[n-1][m-1]>maxx));
}else
{
int sum=0;
if(x+1<n)
{
if(num<k&&w[x][y]>maxx)
{
sum+=dfs(x+1,y,w[x][y],num+1);sum%=mod;
}
sum+=dfs(x+1,y,maxx,num)%mod;sum%=mod;
}
if(y+1<m)
{
if(num<k&&w[x][y]>maxx)
{
sum+=dfs(x,y+1,w[x][y],num+1);sum%=mod;
}
sum+=dfs(x,y+1,maxx,num)%mod;
sum%=mod;
}
return state[x][y][maxx][num]=sum%mod;
}
}
int main()
{
while(cin>>n>>m>>k)
{
memset(state,-1,sizeof(state));
rep(i,0,n-1)
{
rep(j,0,m-1)
{
cin>>w[i][j];
w[i][j]++;//防止出现0
}
}
ll ans=dfs(0,0,0,0)%mod;
cout<<ans<<endl;
}
}