zoukankan      html  css  js  c++  java
  • 地宫取宝|2014年蓝桥杯B组题解析第九题-fishers

    地宫取宝

    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
    资源约定: 峰值内存消耗 < 256M CPU消耗 < 1000ms
    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
    所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
    注意: main函数需要返回0 注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。 注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。
    提交时,注意选择所期望的编译器类型

    思路:dfs模拟走格子,再出口处判断是否满足条件,这里出口处有细节点(代码中解释)

    待改进:上面的思路超时了,只能过42%的数据。要用”记忆化搜索“改进(见文末)

    代码一:

    #include<iostream>
    using namespace std;
    
    long long ans = 0;
    int arr[100][100];
    int n,m,k;
    int have[10010];
    
    //判断是否能拿走当前坐标上的物件 
    bool canTake(int x,int y,int t){
    	for(int i=1;i<=t;i++){
    		if(have[i] >= arr[x][y]){
    			return false;
    		}
    	}
    	return true;
    }
    
    //dfs走格子 
    void dfs(int x,int y,int t){
    	
    	if(x == n && y == m){
    //		(1)可能不算右下角的也正好
    //		(2)如果右下角的比当前的大,算上这一个如果正好也可以增加路径
    		if(t == k+1 || (t==k && canTake(n,m,t))){
    			ans++;
    			ans = ans % 1000000007;
    		}
    		return;
    	}
    	if(canTake(x,y,t)){
    		have[t] = arr[x][y];
    		if(x+1<=n){
    			dfs(x+1,y,t+1);
    		}
    		if(y+1<=m){
    			dfs(x,y+1,t+1);
    		}
    		have[t] = -1;
    	}
    	if(x+1<=n){
    		dfs(x+1,y,t); //走右边 
    	}
    	if(y+1<=m){
    		dfs(x,y+1,t); //走下边 
    	}
    }
    
    int main(){
    	cin>>n>>m>>k;
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			cin>>arr[i][j];
    		}
    	}
    	for(int i=1;i<=k;i++){
    		have[i] = -1;
    	}
    	dfs(1,1,1);//横坐标 纵坐标  件数 
    	cout<<ans<<endl;
    }
    

    记忆型递归:就是“缓存”,使用数组或者map等等。存储当前状态对应的值(这里就是当前dfs参数下对应的方案数),

    为什么要使用记忆型递归?因为中间结果重复过多,为了提高效率。

    代码二:

    #include <stdio.h>
    #include <string.h>
    #define N 1000000007
      int n,m,k;
      int map[50][50];
      int dp[50][50][15][15];//dp数组中记录的是状态   xy坐标 拥有宝物数量 拥有宝物的最大值(这4个可以详尽唯一的描述没一种可能) 
                              //如dp[3][4][5][6]=7 即当在map[3][4]且身上有5件宝物 宝物的最大值是6 是到达终点有7中路径
      
      int dfs(int x,int y,int num,int max)//当前位置   拥有宝物的数量 拥有的宝物的最大值
     {
         if (dp[x][y][num][max]!=-1)//判断这个状态是否已经走过,如果走过就直接用记录的数值计算//因为宝物有可能为0所以定义max时用最小值-1 这就导致无法作为下标使用  实际上如果测试数据中宝物价值没有0
    	                               //将所有的+1 去掉也是可以的   这里的话如果去掉肯定是有些数据不对的,不信可以提交试一下,根本过不了
             return dp[x][y][num][max]; 
           //记忆化的记忆就指的是上面
           
         if(x==n&&y==m){//到达出口 
             if( num==k||(num==k-1&&max<map[x][y]) )  //到达右下角,(1)可能不算右下角的也正好,(2)如果右下角的比当前的大,算上这一个如果正好也可以增加路径 
    		    return dp[x][y][num][max]=1;  //满足条件 当前点到目标有1种方案
             else 
    		 return dp[x][y][num][max]=0;//不满足条件 当前点到目标有0种方案
         }
         long long s=0;
         if(x+1<=n){         //可以向下走
             if (max<map[x][y])
                 s+=dfs(x+1,y,num+1,map[x][y]);//当前位置   拥有宝物的数量 拥有的宝物的最大值                      
             s+=dfs(x+1,y,num,max);            //当前位置   拥有宝物的数量 拥有的宝物的最大值
         }
         if(y+1<=m){         //可以向右走
             if (max<map[x][y])
                 s+=dfs(x,y+1,num+1,map[x][y]);//当前位置   拥有宝物的数量 拥有的宝物的最大值
            s+=dfs(x,y+1,num,max);             //当前位置   拥有宝物的数量 拥有的宝物的最大值
         }
         return dp[x][y][num][max]=s%N;
     }
     int main(){
         scanf("%d%d%d",&n,&m,&k);
         for (int i = 1;i<=n;i++)//初始地宫
             for (int j = 1; j <=m; j++)
                 scanf("%d",&map[i][j]);
         memset(dp,-1,sizeof(dp));
         dfs(1,1,0,-1);
         printf("%d
    ",dp[1][1][0][-1]);
     
         return 0;
     }
    

    解决数组下标为-1,可以将所有值+1

    #include <iostream>
    #include <cstring>
    
    using namespace std;
    const int MOD = 1000000007;
    int n, m, k;
    int data[50][50];
    
    long long ans;
    long long cache[50][50][14][13];
    
    void dfs(int x, int y, int max, int cnt) {
        if (x == n || y == m || cnt > k)
            return;
        int cur = data[x][y];
        if (x == n - 1 && y == m - 1)
        {
            if (cnt == k || (cnt == k - 1 && cur > max)) {
                ans++;
                if (ans > MOD)
                    ans %= MOD;
            }
        }
        if (cur > max) {
            dfs(x, y + 1, cur, cnt + 1);
            dfs(x + 1, y, cur, cnt + 1);
        }
    
        dfs(x, y + 1, max, cnt);
        dfs(x + 1, y, max, cnt);
    
    }
    
    long long dfs2(int x, int y, int max, int cnt) {
    
        if (cache[x][y][max+1][cnt] != -1)
            return cache[x][y][max+1][cnt];
    
        long long ans = 0;
        if (x == n || y == m || cnt > k)
            return 0;
        int cur = data[x][y];
        if (x == n - 1 && y == m - 1)
        {
            if (cnt == k || (cnt == k - 1 && cur > max)) {
                ans++;
                if (ans > MOD)
                    ans %= MOD;
            }
            return ans;
        }
        if (cur > max) {
            ans += dfs2(x, y + 1, cur, cnt + 1);
            ans += dfs2(x + 1, y, cur, cnt + 1);
        }
    
        ans += dfs2(x, y + 1, max, cnt);
        ans += dfs2(x + 1, y, max, cnt);
    
        cache[x][y][max+1][cnt]=ans % MOD;
        return cache[x][y][max+1][cnt];
    }
    
    int main(int argc, const char *argv[]) {
        scanf("%d %d %d", &n, &m, &k);
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                scanf("%d", &data[i][j]);
            }
        }
    //    dfs(0, 0, -1, 0);
    //    printf("%d
    ", ans);
    memset(cache,-1, sizeof(cache));
        printf("%lli
    ", dfs2(0, 0, -1, 0));
        return 0;
    }
    
  • 相关阅读:
    Exception in thread "main" java.util.MissingFormatArgumentException: Format specifier 's'
    抓报错SQL
    10.3.4 direct path read and direct path read temp
    武道与健身——北漂18年(80)
    jquery选择器 之 获取父级元素、同级元素、子元素
    JQuery Show()的几种效果 总有一种是你需要的
    Add method not implemented
    MySQL server version for the right syntax to use near 'info where info.stu_id = 1' at line 1
    Mapped Statements collection does not contain value for WaitMissionMapper.updateWait
    Cause: org.xml.sax.SAXParseException; lineNumber: 32; columnNumber: 14; 注释中不允许出现字符串 "--"
  • 原文地址:https://www.cnblogs.com/fisherss/p/10286587.html
Copyright © 2011-2022 走看看