【蓝桥杯真题】地宫取宝(搜索->记忆化搜索详解)
链接
题目描述
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递归的题目,因为要搜索出每一种可能的情况。并且这个问题不需要回溯(只是在地图上有两个方向可以选择,并且可以选择是否拾起物体,回溯是不取这个物体,这个物体需要另做他用,这个问题不需要考虑)。
接下来就是如何设计这个dfs。
1.首先考虑递归参数。当前走到的地图的位置(i,j),当前选择出的物品的数目cnt,当前的最大物品的质量max。
2.递归出口是走到了地图的出口,如果当前物品数量等于k,ans++,如果当前的物品数量等于k-1并且最后一个物品的重量大于max,ans++。另外一个递归出口是走出边际和选择的物品数量大于k。
dfs代码如下:
void dfs(int i,int j,int cnt,int max){
if(cnt>k||i>n||j>m)return;
if(i==n&&j==m){
if(cnt==k||(cnt==k-1&&maze[i][j]>max))(++ans)%MOD;
return;
}
dfs(i,j+1,cnt,max);
dfs(i+1,j,cnt,max);
if(maze[i][j]>max){
dfs(i+1,j,cnt+1,maze[i][j]);
dfs(i,j+1,cnt+1,maze[i][j]);
}
}
这样会超时,因为在每一点可以选择的方案是2 or 4,这是一个指数级别搜索量。考虑到到达某一个点会有多种方案并且他们的状态是相同的,所以之前的方案存在重复计算,应该设计记忆型搜索,记忆递归函数应该返回一个值。
代码
// 递归改记忆型递归并不复杂,由于存在重复计算的情况
// 重复计算,就是dfs的参数一样,也就是达到目前的状态可能有许多方式,运用记忆化搜索,对于重复的位置只计算一次。
// 所以用一个标记数组,数组的参数与dfs的参数相同
long long dfs2(int i,int j,int cnt,int max){
//查缓存
if(cache[i][j][cnt][max+1]!=-1)return cache[i][j][cnt][max+1];
long long ans=0;//记得一定是局部变量
if(cnt>k||i>n||j>m)return 0;
if(i==n&&j==m){
if(cnt==k||(cnt==k-1&&maze[i][j]>max))++ans;
return ans;
}
ans+=dfs2(i,j+1,cnt,max);
ans+=dfs2(i+1,j,cnt,max);
if(maze[i][j]>max){
ans+=dfs2(i+1,j,cnt+1,maze[i][j]);
ans+=dfs2(i,j+1,cnt+1,maze[i][j]);
}
// 在return之前一定写缓存
cache[i][j][cnt][max+1]=ans%MOD;
return ans%MOD;
}
完整代码
#include<iostream>
#include<cmath>
#include<sstream>
#include<cstring>
using namespace std;
const int MOD=1000000007;
const int N=55;
int maze[N][N];
int vis[N][N];
int n,m,k;
long long ans=0;
int cache[N][N][13][14];
void dfs(int i,int j,int cnt,int max){
if(cnt>k||i>n||j>m)return;
if(i==n&&j==m){
if(cnt==k||(cnt==k-1&&maze[i][j]>max))(++ans)%MOD;
return;
}
dfs(i,j+1,cnt,max);
dfs(i+1,j,cnt,max);
if(maze[i][j]>max){
dfs(i+1,j,cnt+1,maze[i][j]);
dfs(i,j+1,cnt+1,maze[i][j]);
}
}
// 递归改记忆型递归并不复杂,由于存在重复计算的情况
// 重复计算,就是dfs的参数一样,也就是达到目前的状态可能有许多方式,运用记忆化搜索,对于重复的位置只计算一次。
// 所以用一个标记数组,数组的参数与dfs的参数相同
long long dfs2(int i,int j,int cnt,int max){
//查缓存
if(cache[i][j][cnt][max+1]!=-1)return cache[i][j][cnt][max+1];
long long ans=0;//记得一定是局部变量
if(cnt>k||i>n||j>m)return 0;
if(i==n&&j==m){
if(cnt==k||(cnt==k-1&&maze[i][j]>max))++ans;
return ans;
}
ans+=dfs2(i,j+1,cnt,max);
ans+=dfs2(i+1,j,cnt,max);
if(maze[i][j]>max){
ans+=dfs2(i+1,j,cnt+1,maze[i][j]);
ans+=dfs2(i,j+1,cnt+1,maze[i][j]);
}
// 在return之前一定写缓存
cache[i][j][cnt][max+1]=ans%MOD;
return ans%MOD;
}
int main(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
cin>>maze[i][j];
}
memset(cache,-1,sizeof(cache));
// dfs(1,1,0,-1);
cout<<dfs2(1,1,0,-1)<<endl;
//由于max最开始的值为-1,由于数组中不能访问-1.,所以做一个技巧,max+1
return 0;
}
【蓝桥杯真题】地宫取宝(搜索->记忆化搜索详解)的更多相关文章
- 蓝桥杯 2014本科C++ B组 地宫取宝 DFS+记忆化搜索
历届试题 地宫取宝 时间限制:1.0s 内存限制:256.0MB 问题描述 X 国王有一个地宫宝库.是 n x m 个格子的矩阵.每个格子放一件宝贝.每个宝贝贴着价值标签. 地宫的入口在左上角 ...
- 蓝桥杯历届试题 地宫取宝 dp or 记忆化搜索
问题描述 X 国王有一个地宫宝库.是 n x m 个格子的矩阵.每个格子放一件宝贝.每个宝贝贴着价值标签. 地宫的入口在左上角,出口在右下角. 小明被带到地宫的入口,国王要求他只能向右或向下行走. 走 ...
- Java实现 蓝桥杯 历届试题 地宫取宝
问题描述 X 国王有一个地宫宝库.是 n x m 个格子的矩阵.每个格子放一件宝贝.每个宝贝贴着价值标签. 地宫的入口在左上角,出口在右下角. 小明被带到地宫的入口,国王要求他只能向右或向下行走. 走 ...
- 2015 UESTC 搜索专题B题 邱老师降临小行星 记忆化搜索
邱老师降临小行星 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/contest/show/61 Des ...
- skiing(搜索+记忆化搜索)
skiing 时间限制:3000 ms | 内存限制:65535 KB 难度:5 描述 Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当 ...
- P4363 [九省联考2018]一双木棋chess(对抗搜索+记忆化搜索)
传送门 这对抗搜索是个啥玩意儿…… 首先可以发现每一行的棋子数都不小于下一行,且局面可由每一行的棋子数唯一表示,那么用一个m+1进制数来表示当前局面,用longlong存,开map记忆化搜索 然后时间 ...
- CodeForces1249B1/B2-Books Exchange-dfs-一般搜索+记忆化搜索
一般搜索 注意:一般定义成void Books Exchange (easy version) CodeForces - 1249B2 The only difference between eas ...
- Java实现 LeetCode 887 鸡蛋掉落(动态规划,谷歌面试题,蓝桥杯真题)
887. 鸡蛋掉落 你将获得 K 个鸡蛋,并可以使用一栋从 1 到 N 共有 N 层楼的建筑. 每个蛋的功能都是一样的,如果一个蛋碎了,你就不能再把它掉下去. 你知道存在楼层 F ,满足 0 < ...
- bfs记录路径,蓝桥杯真题
题意:在01矩阵中,找到一条从入口到终点的最短路径,并且打印这条路径. 题目链接:http://lx.lanqiao.cn/problem.page?gpid=T291 #include<ios ...
随机推荐
- Codeforces Round #501 (Div. 3) D. Walking Between Houses
题目链接 题意:给你三个数n,k,sn,k,sn,k,s,让你构造一个长度为k的数列,使得相邻两项差值的绝对值之和为sss, ∑i=1n∣a[i]−a[i−1]∣,a[0]=1\sum_{i=1}^n ...
- 设计模式一: 单例模式(Singleton)
简介 单例模式是属于创建型模式的一种(另外两种分别是结构型模式,行为型模式).是设计模式中最为简单的一种. 英文单词Singleton的数学含义是"有且仅有一个元素的集合". 从实 ...
- 设计模式二: 工厂方法(Factory Method)
简介 工厂方法模式是创建型模式的一种, 核心结构有四个角色: 抽象工厂,具体工厂,抽象产品,具体产品; 实现层面上,该模式定义一个创建产品的接口,将实际创建工作推迟到具体工厂类实现, 一个产品对应一个 ...
- Vue导出json数据到Excel表格
一.安装依赖 npm install file-saver --save npm install xlsx --save npm install script-loader --save-dev 二. ...
- 完全卸载删除gitlab
完全卸载删除gitlab 1.停止gitlab gitlab-ctl stop 2.卸载gitlab(注意这里写的是gitlab-ce) rpm -e gitlab-ce 3.查看gitlab进程 p ...
- 18 常用模块 random shutil shevle logging sys.stdin/out/err
random:随机数 (0, 1) 小数:random.random() ***[1, 10] 整数:random.randint(1, 10) *****[1, 10) 整数:random.rand ...
- docker 进阶
docker 常用命令: docker pull hub.c.163.com/library/mysql:latest #这是从网址下载下来mysql镜像 docker run -d -p 88 ...
- 移动 ProgramData\Package Cache 文件夹
装完vs2017 发现C盘快木有空间了… 瞅瞅C盘下有啥能删的好释放下空间 就找到了 Package Cache 文件夹,占用空间接近15G… 查查这个文件夹还不建议删除… (http://super ...
- 使用EasyNetQ简化RabbitMQ操作
关于具体的操作看查看官方文档:https://github.com/EasyNetQ/EasyNetQ 也可以参考中文翻译版本:http://www.cnblogs.com/HuangLiang/p/ ...
- node爬取html乱码
var http = require('http'), iconv = require('iconv-lite'); http.get("http://website.com/", ...