地宫取宝 记忆化搜索

问题 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;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值