zoukankan      html  css  js  c++  java
  • (记忆化递归)地宫取宝

    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;
    }
  • 相关阅读:
    docker配置国内加速器
    pwm原理与stm32控制
    【C语言】赋值表达式自增自减逗号表达式
    linux下利用paho.mqtt.c进行mqtt开发 #c编程
    linux下tcp #c编程
    windows下的linux子系统虚拟串口的使用
    linux下搭建mqtt服务器(mosquitto)
    linux下paho.mqtt.c下载安装
    树莓派&mysql数据库
    vscode+mysql数据库编程
  • 原文地址:https://www.cnblogs.com/xusi/p/12468013.html
Copyright © 2011-2022 走看看