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. Springboot与Maven多环境配置文件夹解决方案

    Profile用法 我们在application.yml中为jdbc.name赋予一个值,这个值为一个变量 jdbc: username: ${jdbc.username} Maven中的profil ...

  2. Flutter环境搭建以及快捷命令

    Flutter环境搭建 配置环境变量 用户变量 FLUTTER_STORAGE_BASE_URL : https://storage.flutter-io.cn PUB_HOSTED_URL : ht ...

  3. OpenMP Programming

    一.OpenMP概述 1.OpenMP应用编程接口API是在共享存储体系结构上的一个编程模型 2.包含 编译制导(compiler directive).运行库例程(runtime library). ...

  4. Head First设计模式——中介者模式和备忘录模式

    中介者 中介者模式:使用中介者来集中相关对象之间复杂的沟通方式和控制方式. Bob有一个自动屋,当他的闹钟响了只有,闹钟会告诉咖啡壶开始煮咖啡.后来客户不断的提出许多新需求:周末不要提供咖啡.下班后需 ...

  5. 【python】提取sql语句中的表名

    前言 最近刚学python,写一个小工具时需要提取sql语句中表名,查询一番后找到一篇文章挺不错的,mark一下 PS.那篇文章是转载的,且没有标注转载自哪里 正文 import ply.lex as ...

  6. 菜鸟对java和Go的理解

    1.go对比java go通过结构体嵌套+接口实现类似面向对象中的继承和多态.个人认为尤其是go的接口抓住了多态的本质.而Go提倡的面向接口的思想也可能使得架构上更加解耦. 2.关于Go不要通过共享内 ...

  7. 第3章 C++中的C

    用union节省内存 使用场合:有时一个程序会使用同一个变量处理不同的数据类型,对于这种情况,有两种选择:可以创建一个struct,其中包含所有可能的不同类型的数据:也可以使用联合union,它能把所 ...

  8. 记一次在新服务器上搭建lnmp的过程

    背景: 前不久阿里云在做活动,200+一台服务器三年,于是果断入手了一台. 今天有空就在服务器上把lnmp环境给装了,之前为了了解安装过程,在别的机器上尝试过单独安装nginx.mysql.php,虽 ...

  9. 使用express+shell在服务器上搭建一套简单的前端部署系统

    前言 个人项目越来越多,部署需要频繁操作服务器,所以手动搭建一套简单的部署系统. 效果如图 其中包含 原生html+css+js项目,单页面react, vue, angular项目,实现了一键打包发 ...

  10. 【转】分布式架构的演进(JavaWeb)

    作者:李小翀 链接:https://www.zhihu.com/question/22764869/answer/31277656 来源:知乎 1.初始 初始阶段 的小型系统 应用程序.数据库.文件等 ...