zoukankan      html  css  js  c++  java
  • 试题 历届试题 地宫取宝(dfs、dp)

    问题描述
      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
    思路
    1.记忆化dfs
    很典型的搜索题目,开一个四维数组,分别存储位置和手上物品数量和最大价值,由于物品价值可以是0,初始化最大价值为-1;
    本质是还是取和不取,更新各种状态,注意出口和记忆化即可。
    #include<bits/stdc++.h>
    using namespace std;
    int n,m,k;;
    long long int a[55][55][20][20];
    int w[55][55];
    const int inf=0x3f3f3f;
    int def=1000000007;
    int dfs(int x,int y,int c,int maxx)
    {
        long long int ans=0;
        if(a[x][y][c][maxx+1]!=-1)return a[x][y][c][maxx+1];
        if(c>k)return 0;
        if(x==n-1&&y==m-1){
            if(c==k||c==k-1&&w[x][y]>maxx){
                ///ans++;
                return a[x][y][c][maxx+1]=1;
            }
            return a[x][y][c][maxx+1]=0;
        }
        if(x<n-1){
            if(w[x][y]>maxx){
                ans+=dfs(x+1,y,c+1,w[x][y]);
            }
            ans+=dfs(x+1,y,c,maxx);
        }
        if(y<m-1){
            if(w[x][y]>maxx){
                ans+=dfs(x,y+1,c+1,w[x][y]);
            }
            ans+=dfs(x,y+1,c,maxx);
        }
        return a[x][y][c][maxx+1]=ans%def;
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&k);
        memset(a,-1,sizeof(a));
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++)scanf("%d",&w[i][j]);
        }
        cout<<dfs(0,0,0,-1)%def<<endl;
    }

     2.dp

    dp[i][j][c][w]维护一个从左上角到ij点取了c件物品且最大的一项是w的方案数,每一项的方案数都是由其左边和上边的方案数转移而来。

    此时我们把左边和上边的方案数都转移到当前位置。

    分为选当前这件物品、不选当前物品,不选的话把所有相同状态转移即可。

    选的话 需要把所有小于当前价值且物品数少一的方案累加。

    #include<bits/stdc++.h>
    using namespace std;
    int dp[55][55][15][15];
    int w[55][55];
    int n,m,k;
    const int mod = 1000000007;
    int main(){
        cin>>n>>m>>k;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                cin>>w[i][j];
                w[i][j]++;
    
            }
        }
        ///dp[i][j][c][w]维护一个从左上角到ij点取了k件物品且最大的一项是w的方案数
        dp[1][1][0][0]=1;
        dp[1][1][1][w[1][1]]=1;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){///枚举每个点
                for(int c=0;c<=k;c++){///枚举件数
                    for(int d=0;d<=13;d++){
                        dp[i][j][c][d]=(dp[i][j][c][d]+dp[i-1][j][c][d])%mod;
                        dp[i][j][c][d]=(dp[i][j][c][d]+dp[i][j-1][c][d])%mod;
                        if(c>0&&d==w[i][j]){
                            for(int f=0;f<w[i][j];f++){///选了当前物品
                                dp[i][j][c][d]=(dp[i][j][c][d]+dp[i-1][j][c-1][f])%mod;
                                dp[i][j][c][d]=(dp[i][j][c][d]+dp[i][j-1][c-1][f])%mod;
                            }
                        }
                    }
                }
            }
        }
        long long res=0;
        for(int d=0;d<=13;d++){
            res+=dp[n][m][k][d];
            res%=mod;
        }
        cout<<res<<endl;
        return 0;
    }
  • 相关阅读:
    深入JVM系列(二)之GC机制、收集器与GC调优
    使用C++ Builder XE5获取Sensor值之Light Sensor
    Xilinx FFT IP v9.0 使用
    用十句简单英语激活你的口语
    Android编译系统中的Android.bp【转】
    【定制Android系统】Android O 在ROM中添加自己的 so 库(1)——Android.mk 与 Android.bp 的区别【转】
    高通平台framework,hal,kernel打开log【转】
    如何在andorid native layer中加log function.【转】
    Android Java层,Native层,Lib层打印Log简介【转】
    Android 系统(64)---Android中m、mm、mmm、mma、mmma的区别【转】
  • 原文地址:https://www.cnblogs.com/mohari/p/12958170.html
Copyright © 2011-2022 走看看