BFS、DFS ——J - Nightmare
J - Nightmare
Ignatius had a nightmare last night. He found himself in a labyrinth
with a time bomb on him. The labyrinth has an exit, Ignatius should
get out of the labyrinth before the bomb explodes. The initial
exploding time of the bomb is set to 6 minutes. To prevent the bomb
from exploding by shake, Ignatius had to move slowly, that is to move
from one area to the nearest area(that is, if Ignatius stands on (x,y)
now, he could only on (x+1,y), (x-1,y), (x,y+1), or (x,y-1) in the
next minute) takes him 1 minute. Some area in the labyrinth contains a
Bomb-Reset-Equipment. They could reset the exploding time to 6
minutes.Given the layout of the labyrinth and Ignatius’ start position, please
tell Ignatius whether he could get out of the labyrinth, if he could,
output the minimum time that he has to use to find the exit of the
labyrinth, else output -1.Here are some rules:
- We can assume the labyrinth is a 2 array.
- Each minute, Ignatius could only get to one of the nearest area, and he should not walk out of the border, of course he could not walk
on a wall, too.- If Ignatius get to the exit when the exploding time turns to 0, he can’t get out of the labyrinth.
- If Ignatius get to the area which contains Bomb-Rest-Equipment when the exploding time turns to 0, he can’t use the equipment to reset the
bomb.- A Bomb-Reset-Equipment can be used as many times as you wish, if it is needed, Ignatius can get to any areas in the labyrinth as many
times as you wish.- The time to reset the exploding time can be ignore, in other words, if Ignatius get to an area which contain Bomb-Rest-Equipment, and the
exploding time is larger than 0, the exploding time would be reset to
Input
The input contains several test cases. The first line of the input is
a single integer T which is the number of test cases. T test cases
follow. Each test case starts with two integers N and M(1<=N,Mm=8)
which indicate the size of the labyrinth. Then N lines follow, each
line contains M integers. The array indicates the layout of the
labyrinth. There are five integers which indicate the different type
of area in the labyrinth: 0: The area is a wall, Ignatius should not
walk on it. 1: The area contains nothing, Ignatius can walk on it.
2: Ignatius’ start position, Ignatius starts his escape from this
position. 3: The exit of the labyrinth, Ignatius’ target position.
4: The area contains a Bomb-Reset-Equipment, Ignatius can delay the
exploding time by walking to these areas.
Output
For each test case, if Ignatius can get out of the labyrinth, you
should output the minimum time he needs, else you should just output
-1. Sample Input
3
3 3
2 1 1
1 1 0
1 1 3
4 8
2 1 1 0 1 1 1 0
1 0 4 1 1 0 4 1
1 0 0 0 0 0 0 1
1 1 1 4 1 1 1 3
5 8
1 2 1 1 1 1 1 4
1 0 0 0 1 0 0 1
1 4 1 0 1 1 0 1
1 0 0 0 0 3 0 1
1 1 4 1 1 1 1 1
Sample Output
4
-1
13
bfs思路如下 :
这一题,起始相较于其他迷宫题,最难想的是 到底要不要进行标记?如果标记应该标记那些点?标记的点对该题的要求是否有影响?(这题的主要思路就 处理标记点的问题 直接看代码吧)
题解如下:
//炸弹重置
//dfs 逃出炸弹迷宫
#include<stdio.h>
#include<queue>
using namespace std;
int m,n;
int mov[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};
int map[10][10]; //存地图
int pos[1][2]; //存储人的初始位置
struct Node
{
int x,y;
int time; //剩余时间
int step; //所用步数
}st,en;
queue<Node> q;
void bfs()
{
while(! q.empty()) //每次调用bfs清空 q队列
q.pop();
//赋值、压入队列
st.x = pos[0][0];
st.y = pos[0][1];
st.time = 6;
st.step = 0;
q.push(st);
while(! q.empty())
{
st = q.front();
q.pop();
for(int i=0;i<4;i++)
{
en = st;
en.x += mov[i][0];
en.y += mov[i][1];
en.time--;
if(en.x<0 || en.y<0 || en.x>=m || en.y>=n || !map[en.x][en.y]) //与其他的BFS题不同,这一题不需要,单独定义一个二数组标记某些点是否走过(如果 这样做了 会影响做题)
continue;
if(en.time == 0) //走到下一个点剩余的时间为 0 ,这一步是不可以走
break;
if(map[en.x][en.y] == 4) //更新时间,并对(en.x,en.y)这个点做标记(只有炸弹重置器位于点需要做的标记)
{ //其实这一题最难想的部分就是是否要标记,如果标记了会怎么样不标记会怎样,对于这一题 我们应该不单独定义二维数组进行标记,只需要在原图上,对有 时间重置器的点 进行标记就可以了,
en.time = 6; //首先先解释 为什么要标记 有时间重置器的点 ,因为要想获得最短逃出时间,有重置器的点应该只能走一次,重复走这点是没有意义的反而 使最短逃出时间增加(当然重复走其他点 也是这样的),所以要标记 有重置器的点
map[en.x][en.y] = 0; //到这里我们还是有个疑问,为什么 除重置器以外的点不进行标记???,如果不标记会不会造成 bfs函数一直循环运行,没有出口(终止点)???,首先解释:不标记其它点,如果标记某个点,这个点可能会影响(这个影响是 指标记后的点就不能再走了,而有的情况 是需要 再次经过这个点的) 其它 经过重置器的点的这个方案正常的向下一层蔓延(该题的最后一个样例就出现了该问题)从而影响答案,
} //再解释第二个问题,为什么不标记 这个dfs不会一直运行下去,因为这题有一个 if(en.time == 0) break;终止条件,虽然 地图上的点出 有重置器外的点均没有进行标记,所以有些点会 多 重复进行走几遍,一旦这些点 的剩余时间为零(注意此时也没 重置器为 这些点刷新时间 因为重置器点已经被标记不可再次访问) 这些点就结束不会再往下一层进行蔓延,这样程序就不会一直运行下去
en.step++;
if(map[en.x][en.y] == 3) //判断是否到达 出口
{
printf("%d\n",en.step);
return;
}
q.push(en);
}
}
printf("-1\n");
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&m,&n);
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
{
scanf("%d",&map[i][j]);
if(map[i][j] == 2)
pos[0][0] = i,pos[0][1] = j;
}
bfs();
}
return 0;
}
dfs思路 如下:
看到这一题,我们正常的思维就是在用dfs的时候对迷宫进行,进行标记,使访问过的点不能被访问,但这样却会影响 有些点走过了还需要被走,但是如果我们不进行标记,递归又会无限调用自己,为避免这种情况,我们可以开两个数组Step、Time分别存储 目前到某个点最优的 步数和时间,通过 某一种方案 在某到某一点的 步数和时间情况与当前最优进行比较,如果不是最优,就可以直接终止该方案,从而避免无限递归调用问题,最后在所有可行方案中选出最优即可
题解如下:
#include<iostream>
using namespace std;
int m,n;
int mov[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};
int map[15][15]; //存地图
int Time[15][15]; //存地图上某个点被到达的时间,以供与递归调用中产生的一些方案到该点的时间进行比较,从而达到减枝的目的
int Step[15][15]; //存地图上某个点被到达的时的步数,以供与递归调用中产生的的一些方案到该点的步数进行比较,从而达到减枝的目的
int s_x,s_y; //起始位置
int min_step; //可行方案中的最小步数
int flag = 0;
struct Node
{
int x,y;
int time;
int step;
};
void dfs(Node node)
{
if(node.step >= min_step) //剪枝1.
return;
if(node.step >= Step[node.x][node.y] && Time[node.x][node.y] >= node.time) //剪枝2.通过当前 某种方案 走到该点的步数、走到该点剩余的时间 与 与存在 数组Step、Time的目前最优解 进行比较
return; //如果条件成立 说明该方案 走到该的点的情况不是最优的,所以retunr去除这种情况;如果不成立说明该方案最有,则替换数组Step、Time中的值
Step[node.x][node.y] = node.step;
Time[node.x][node.y] = node.time;
if(map[node.x][node.y] == 3) //递归终止条件
{
flag = 1;
if(min_step > node.step)
min_step = node.step;
return;
}
Node temp;
for(int i=0;i<4;i++)
{
temp = node;
temp.x += mov[i][0];
temp.y += mov[i][1];
if(temp.x>=0 && temp.y>=0 && temp.x<m && temp.y <n && map[temp.x][temp.y]) //判断这一步是否可以走
{
temp.time--;
if(temp.time == 0) //剪枝3.
return;
temp.step++;
if(map[temp.x][temp.y] == 4)
temp.time = 6; //注意⚠️:这里不要对(temp.x,temp.y)这个点做标记(会出现错误,虽然我也不知道为什么出现错误)
dfs(temp);
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
flag = 0;
min_step = 1e9;
scanf("%d%d",&m,&n);
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
{
scanf("%d",&map[i][j]);
if(map[i][j] == 2)
s_x = i,s_y = j;
Time[i][j] = 0;
Step[i][j] = 1e9;
}
Node tem;
tem.x = s_x;
tem.y = s_y;
tem.time = 6;
tem.step = 0;
dfs(tem);
if(flag == 1)
cout<<min_step<<endl;
else
cout<<"-1\n";
}
return 0;
}
BFS、DFS ——J - Nightmare的更多相关文章
- 算法学习之BFS、DFS入门
算法学习之BFS.DFS入门 0x1 问题描述 迷宫的最短路径 给定一个大小为N*M的迷宫.迷宫由通道和墙壁组成,每一步可以向相邻的上下左右四格的通道移动.请求出从起点到终点所需的最小步数.如果不能到 ...
- 【算法】二叉树、N叉树先序、中序、后序、BFS、DFS遍历的递归和迭代实现记录(Java版)
本文总结了刷LeetCode过程中,有关树的遍历的相关代码实现,包括了二叉树.N叉树先序.中序.后序.BFS.DFS遍历的递归和迭代实现.这也是解决树的遍历问题的固定套路. 一.二叉树的先序.中序.后 ...
- 九度OJ 1091:棋盘游戏 (DP、BFS、DFS、剪枝)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:1497 解决:406 题目描述: 有一个6*6的棋盘,每个棋盘上都有一个数值,现在又一个起始位置和终止位置,请找出一个从起始位置到终止位置代 ...
- 搜索(BFS、DFS、回溯)
这类题是最简单的了都是一个套路,不像动态规划一类题一个套路,没做过就是不会也极难想出来. 一.BFS 解决的问题:用来初始点解决到指定点的最短路径问题,因为图的每一层上的点到初始点的距离相同.(注意是 ...
- 题解报告:poj 1426 Find The Multiple(bfs、dfs)
Description Given a positive integer n, write a program to find out a nonzero multiple m of n whose ...
- BFS、DFS与选课问题(拓扑排序)
1选课问题 Leetcode上有这样一道题:有代号0,1,2……n-1的n门课程.其中选择某些课程需要另一些课程作为前提条件.用一组pair来表示这些条件:[1,0],[1,2],表示如果要选修课程1 ...
- BFS 、DFS 解决迷宫入门问题
问题 B: 逃离迷宫二 时间限制: 1 Sec 内存限制: 128 MB提交: 12 解决: 5[提交][状态][讨论版] 题目描述 王子深爱着公主.但是一天,公主被妖怪抓走了,并且被关到了迷宫. ...
- BFS、DFS、先序、中序、后序遍历的非递归算法(java)
一 广度优先遍历(BFS) //广度优先遍历二叉树,借助队列,queue public static void bfs(TreeNode root){ Queue<TreeNode> qu ...
- POJ 1985.Cow Marathon-树的直径-树的直径模板(BFS、DFS(vector存图)、DFS(前向星存图))
Cow Marathon Time Limit: 2000MS Memory Limit: 30000K Total Submissions: 7536 Accepted: 3559 Case ...
随机推荐
- nginx前端服务部署
一.登录服务器 登录跳板机 执行list,列出所有机器 执行dssh 机器序号,如dssh 1,选择机器 二. 创建nginx配置文件 进入nginx配置目录:cd usr/local/nginx/c ...
- 量子计算机编程(二)——QPU基础函数
第二部分主要是QPU的基础功能,第一部分就像是我们有了哪些基本的语句,第二部分就是我们能写一些简单基础的函数,一些小模块,第三部分就是他的应用了. 先来看一下一个简单量子应用的结构: 第一步,将量子态 ...
- 7,MapReduce基础
目录 MapReduce基础 一.关于MapReduce 二.MapReduce的优缺点 三.MapReduce的执行流程 四.编写MapReduce程序 五.MapReduce的主要执行流程 Map ...
- postman小工具
进入lmm后,做接口测试使用的是postman,以前稍微接触过,但是不是很会用,这里就自学顺便总结一下,以便以后或者能帮助到别人,如果有什么不同的意见或者有错误,请毫不客气的指出,感谢! 推荐一篇博客 ...
- 如何安装vue-devtool调试工具
1.从git上下载工具压缩包,github下载地址:https://github.com/vuejs/vue-devtools: 2.打开cmd,切换到下载的文件目录下:npm install---- ...
- Spark入门(二)--如何用Idea运行我们的Spark项目
用Idea搭建我们的Spark环境 用IDEA搭建我们的环境有很多好处,其中最大的好处,就是我们甚至可以在工程当中直接运行.调试我们的代码,在控制台输出我们的结果.或者可以逐行跟踪代码,了解spark ...
- 练习div出现的小问题
一.出现图片不显示状况1.class中设定的名字不对2.在高单位后面出现了 “:“ 所以也不显示3.上一个div盒子没有写结束标签 4.在添加背景图,把height的值改成auto后不显示,填上具体数 ...
- dict的常用方法
注:dic表示定义的一个字典变量,如:dic = {'name': 'shawn', 'age': 18} 增: 1. dic['love'] = 'girl' 直接通过新的键值对进行添加 dic ...
- 基于.NetCore3.1搭建项目系列 —— 使用Swagger做Api文档 (上篇)
前言 为什么在开发中,接口文档越来越成为前后端开发人员沟通的枢纽呢? 随着业务的发张,项目越来越多,而对于支撑整个项目架构体系而言,我们对系统业务的水平拆分,垂直分层,让业务系统更加清晰,从而产生一系 ...
- 玩转控件:封装Dev的LabelControl和TextEdit
俗话说的好:"工欲善其事必先利其器",作为软件攻城狮也是同样道理,攻城狮开发的软件目的是简化客户的操作,让客户动动手指就可以完成很多事情,减少人力成本.这也是系统/软件存在的目的. ...