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:

  1. We can assume the labyrinth is a 2 array.
  2. 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.
  3. If Ignatius get to the exit when the exploding time turns to 0, he can’t get out of the labyrinth.
  4. 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.
  5. 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.
  6. 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的更多相关文章

  1. 算法学习之BFS、DFS入门

    算法学习之BFS.DFS入门 0x1 问题描述 迷宫的最短路径 给定一个大小为N*M的迷宫.迷宫由通道和墙壁组成,每一步可以向相邻的上下左右四格的通道移动.请求出从起点到终点所需的最小步数.如果不能到 ...

  2. 【算法】二叉树、N叉树先序、中序、后序、BFS、DFS遍历的递归和迭代实现记录(Java版)

    本文总结了刷LeetCode过程中,有关树的遍历的相关代码实现,包括了二叉树.N叉树先序.中序.后序.BFS.DFS遍历的递归和迭代实现.这也是解决树的遍历问题的固定套路. 一.二叉树的先序.中序.后 ...

  3. 九度OJ 1091:棋盘游戏 (DP、BFS、DFS、剪枝)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:1497 解决:406 题目描述: 有一个6*6的棋盘,每个棋盘上都有一个数值,现在又一个起始位置和终止位置,请找出一个从起始位置到终止位置代 ...

  4. 搜索(BFS、DFS、回溯)

    这类题是最简单的了都是一个套路,不像动态规划一类题一个套路,没做过就是不会也极难想出来. 一.BFS 解决的问题:用来初始点解决到指定点的最短路径问题,因为图的每一层上的点到初始点的距离相同.(注意是 ...

  5. 题解报告: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 ...

  6. BFS、DFS与选课问题(拓扑排序)

    1选课问题 Leetcode上有这样一道题:有代号0,1,2……n-1的n门课程.其中选择某些课程需要另一些课程作为前提条件.用一组pair来表示这些条件:[1,0],[1,2],表示如果要选修课程1 ...

  7. BFS 、DFS 解决迷宫入门问题

    问题 B: 逃离迷宫二 时间限制: 1 Sec  内存限制: 128 MB提交: 12  解决: 5[提交][状态][讨论版] 题目描述 王子深爱着公主.但是一天,公主被妖怪抓走了,并且被关到了迷宫. ...

  8. BFS、DFS、先序、中序、后序遍历的非递归算法(java)

    一 广度优先遍历(BFS) //广度优先遍历二叉树,借助队列,queue public static void bfs(TreeNode root){ Queue<TreeNode> qu ...

  9. POJ 1985.Cow Marathon-树的直径-树的直径模板(BFS、DFS(vector存图)、DFS(前向星存图))

    Cow Marathon Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 7536   Accepted: 3559 Case ...

随机推荐

  1. Simple: 一个支持中文和拼音搜索的 sqlite fts5插件

    之前的工作关系,需要在手机上支持中文和拼音搜索.由于手机上存储数据一般都是用 sqlite,所以是基于 sqlite3 fts5 来实现.这段时间再次入门 c++,所以想用 c++ 实现一下,一来用于 ...

  2. 【01】openLayers 第一个地图

    效果: 代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <t ...

  3. form里面文件上传并预览

    其实form里面是不能嵌套form的,如果form里面有图片上传和其他input框,我们希望上传图片并预览图片,然后将其他input框填写完毕,再提交整个表单的话,有两种方式! 方式一:点击上传按钮的 ...

  4. office一直提示配置进度与图标问题

    原来安装了wps office,广告太烦,于是卸载了wps安装Microsoft office 2010,安装完成后每次打开excel文件都要重新安装配置,修改注册表norereg和设置兼容模式都不行 ...

  5. go学习第五天、运算符

    算术运算符 下表列出了所有Go语言的算术运算符.假定 A 值为 10,B 值为 20 运算符 描述 实例 + 相加 A + B 输出结果 30 - 相减 A - B 输出结果 -10 * 相乘 A * ...

  6. AndroidStudio提高编译速度的几种方法

    第一种: 减少依赖库的使用,让代码更加精简.对于一些必须依赖的库要尽量使用jar包或者依赖库,这样他每次就会在本地直接加载,而不是每次翻墙检查更新 第二种: 打开Android Studio,选择菜单 ...

  7. mui switch 点击事件不冒泡

    工作上遇到一个问题 手机移动端app,采用mui框架,要求左边是手机号码,右边是switch开关,并且点击标题的时候,可以展开下面人员的基本信息. 采用了折叠面板. 先上图如下: 开始时出现的问题是: ...

  8. 覆盖io.spring.platform管理的版本号

    使用io.spring.platform时,它会管理各类经过集成测试的依赖版本号.想要覆盖其中某个依赖的版本号个: https://www.cnblogs.com/ld-mars/p/11818252 ...

  9. Recover刷机简介

    Recovery Recovery是一种可以对安卓手机内部的数据文件进行修改的模式,类似电脑的PE.不同的recovery有不同的功能.使用recovery可以说是刷机(卡刷)的基础,想要比较顺畅的刷 ...

  10. [bash]http serevr部署wordpress

    #!/bin/bash # echo "close selinux…" sed -i 's/Enforcing/disabled/' /etc/sysconfig/selinux ...