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. 关于独立部署web项目到tomcat服务器详情

    步骤: 1.设置端口号:找到所解压的tomcat的目录下中的conf文件夹,再用editPlus打开conf文件夹中的server.xml文件,tomcat初始端口为8005,8080,8009,如果 ...

  2. 利用wps创建有目录的PDF/word

    为什么要创建: 在阅读一些行业规范或者很长的文件,像是项目管理方案时,非常麻烦,定位需要重新返回目录去.--->所以我想能不能创建一个带目录的PDF,可以点击直接跳转,那就方便多了. 如何创建: ...

  3. 机器学习 - LSTM应用之sequence generation

    概述 LSTM在机器学习上面的应用是非常广泛的,从股票分析,机器翻译 到 语义分析等等各个方面都有它的用武之地,经过前面的对于LSTM结构的分析,这一节主要介绍一些LSTM的一个小应用,那就是sequ ...

  4. 在vue中实现锚点定位功能

    场景如下: 今天早上看到需求方新提的一个需求,这是一份网上答卷,点击题数要实现滚动到对应题目的位置: 注意点:每题题目的高度是不受控制的,你可以取到想跳转的index:(我再循环题目时做了index+ ...

  5. 从 Spring 的环境到 Spring Cloud 的配置

    需求 不知不觉,web 开发已经进入 “微服务”.”分布式” 的时代,致力于提供通用 Java 开发解决方案的 Spring 自然不甘人后,提出了 Spring Cloud 来扩大 Spring 在微 ...

  6. oracle去除重复数据与oracle分页

    一.去除oracle中重复数据,可以使用rowid列,rowid列是一个伪列,该列在数据库中灭一个表中都有,但是我们查询数据库的时候,默认都没有给我们返回这一列,这一列用来区分数据库中的每一行时间,可 ...

  7. Python——项目-小游戏2-动画绘制

    实现游戏循环还有事件的监听 在上一讲中 你需要完成这样的这样的效果, 如果你还没有完成,请不要继续往下阅读!!切记切记切记.,重要的事情说三遍 我们来看一下什么是游戏循环 所谓的游戏循环很好的理解 就 ...

  8. Bisecting GlcNAc is a general suppressor of terminal modification of N-glycan (解读人:王茹凯)

    文献名:Bisecting GlcNAc is a general suppressor of terminal modification of N-glycan(平分GlcNAc是N-聚糖末端修饰的 ...

  9. JavaScript(8)--- 闭包

    JavaScript(8)--- 闭包 理解闭包 我的理解是:闭包就是能够读取其他函数内部变量的函数.由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以简单这样理解 &q ...

  10. Android之注册界面练习

    今天要分享的是一个安卓注册小练习,记录一下自己的学习. 做一个注册页面. 要求填入用户如下信息: 用户名.密码.确认密码.性别(单选).爱好(多选,包括至少六个选项,如音乐.美术.阅读.篮球等).em ...