(记忆化递归)地宫取宝

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

 

解法一:暴力dfs

#include <cstdio>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <math.h>

using namespace std;
const int inf=0x7fffffff;
const long long mod=1e9+7;
const double PI=acos(-1);
bool vis[105];
int a[105][105];
int n,m,k;
long long ans;
void dfs(int x,int y,int p,int mx){
    if(p>k||x>=n||y>=m){
        return;
    }
    if(x==n-1&&y==m-1){            //到最后一个格子 
        if(p==k){                   //到最后格子前已经取了 k 个物品 
            ans++;
            ans=ans%mod;
        }
        if(p==k-1&&a[x][y]>mx){      //到最后格子还没有取到 k 个物品,但是最后一个格子的值比此时的最大值大  就可以取最后一个格子取满k个数 
            ans++;
            ans=ans%mod;
        }
        return;
    }
    if(a[x][y]>mx){                 //此时的格子价值大于现在的最大值 可以拿该物品 
        dfs(x+1,y,p+1,a[x][y]);
        dfs(x,y+1,p+1,a[x][y]);
    }
    dfs(x+1,y,p,mx);             //不管格子的价值是不是很大  都可以不拿该物品 
    dfs(x,y+1,p,mx);
}
int main()
{    
    scanf("%d %d %d",&n,&m,&k);
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            scanf("%d",&a[i][j]);
        }
    }
    dfs(0,0,0,-1);             //格子的价格可能为 0  所以最初传入最大值-1 才可以更新 
    cout<<ans;
    return 0;
}

 

 

解法二:记忆化递归

可以这么理解:先用暴力递归做出来,然后把它转换为记忆化搜索,即在头查表,在尾写表,表的参数和dfs的参数一致。

然后,就是用一个数组来记录计算过的值

接着,你再在递归函数头部——if (这个数组的值不为初始值) return 这个值;最后,后面的递归返回值里——“数组=”递归返回值。

#include<iostream>
#include<string.h>
#include<math.h>

using namespace std;
int n,m,k; 
int ans;
int mod=1e9+7;
int a[105][105];
int cache[50][50][20][20]; 
bool vis[105];  
long long dfs(int x,int y,int cot,int mx){
    //记忆型递归主要是改开头和结尾 
    if(cache[x][y][cot][mx+1]!=-1){       //查缓存 
        return cache[x][y][cot][mx+1];
    } 
    long long ans=0;
    if(x>=n||y>=m||cot>k){
        return 0;
    }
    if(x==n-1&&y==m-1){                 //到最后一个格子 
        if(cot==k){                     //到最后格子前已经取了 k 个物品 
            ans++;
            ans=ans%mod;
        }
        if(cot==k-1&&a[x][y]>mx){       //到最后格子还没有取到 k 个物品,但是最后一个格子的值比此时的最大值大  就可以取最后一个格子取满k个数 
            ans++;
            ans=ans%mod;
        }
        return ans;
    }
    if(a[x][y]>mx){
        ans+=dfs(x+1,y,cot+1,a[x][y]);
        ans+=dfs(x,y+1,cot+1,a[x][y]);
    }
    ans+=dfs(x+1,y,cot,mx);
    ans+=dfs(x,y+1,cot,mx);
    
    cache[x][y][cot][mx+1]=ans%mod;      //写缓存 
    return ans%mod;                      //添加返回值 
}
int main(){
    cin>>n>>m>>k;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>a[i][j];
        }
    }
    memset(cache,-1,sizeof(cache));
    cout<<dfs(0,0,0,-1);
    return 0;
}

 

posted @ 2020-03-12 11:33  Maxwell·  阅读(312)  评论(0编辑  收藏  举报