Rescue(BFS时间最短 另开数组或优先队列)
Angel was caught by the MOLIGPY! He was put in prison by Moligpy. The prison is described as a N * M (N, M <= 200) matrix. There are WALLs, ROADs, and GUARDs in the prison.
Angel's friends want to save Angel. Their task is: approach Angel. We assume that "approach Angel" is to get to the position where Angel stays. When there's a guard in the grid, we must kill him (or her?) to move into the grid. We assume that we moving up, down, right, left takes us 1 unit time, and killing a guard takes 1 unit time, too. And we are strong enough to kill all the guards.
You have to calculate the minimal time to approach Angel. (We can move only UP, DOWN, LEFT and RIGHT, to the neighbor grid within bound, of course.)
First line contains two integers stand for N and M.
Then N lines follows, every line has M characters. "." stands
for road, "a" stands for Angel, and "r" stands for each of Angel's
friend.
Process to the end of the file.
Output
For each test case, your program should output a single
integer, standing for the minimal time needed. If such a number does no
exist, you should output a line containing "Poor ANGEL has to stay in
the prison all his life."
Sample Input
7 8
#.#####.
#.a#..r.
#..#x...
..#..#.#
#...##..
.#......
........
Sample Output
13
题目意思:Angel被抓住了,关在监狱里面,他的朋友想要去营救他,他的朋友可以上下左右移动一步,每移动一步耗时一个时间单位,监狱里还有警卫x,杀死一个警卫也要耗时一个时间单位,监狱里面还有不能走的围墙#,求他的朋友找到Angel至少需要多少时间。
解题思路:我们知道BFS适合用来求最短路,求出来的解是步数最少的解,但是这道题步数最少的解并不是最优解,我们会发现在BFS扩展节点时,单纯遇到守卫就直接对步数加一是不影响从r到a的距离的,想到这里,单纯的BFS好像就不行了,这里就需要对BFS进行一些处理,这里我们再定义一个数组mintime,mintime[i][j]代表Angel朋友走到(i,j)位置所需要的最少时间,在BFS搜索过程中,从当前位置走到临近位置(x,y)时,只有当这种走法比之前走到(x,y)位置所花时间更少,才会把当前走到(x,y)位置所代表表示的状态入队列,否则是不会入队列的。在本代码中并没有使用标明各个位置是否访问过的状态数组vis,也没有在BFS过程中将访问过的相邻位置设置为不可再访问,但BFS也不会无限搜索下去,因为从某个位置出发判断是否需要将它的相邻位置(x,y)入队列时,条件是这种走法比之前走到(x,y)位置所花时间更少;如果所花时间更少,则(x,y)位置会重复入队,但不会无穷下去,因为到达(x,y)位置的最少时间肯定是有下界的。
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int n,m;
struct point
{
int x;
int y;
int step;
int time;
};
queue<point>q;
char maps[][];
int mintime[][];///走到每个位置所需的最少时间
int dix[]= {,-,,};
int diy[]= {,,,-};
int ax,ay;///Angel位置
int judge(int x,int y)///判断能否移动到相邻的位置
{
if(x>=&&x<n&&y>=&&y<m&&maps[x][y]!='#')///排除边界和墙
{
return ;
}
return ;
}
int BFS(point s)
{
int i,a,b;
q.push(s);
point hd;
while(!q.empty())
{
hd=q.front();
q.pop();
for(i=; i<; i++)
{
a=hd.x+dix[i];
b=hd.y+diy[i];
if(judge(a,b))
{
point t;///向第i方向后走一步的位置
t.x=a;
t.y=b;
t.step=hd.step+;
t.time=hd.time+;
if(maps[a][b]=='x')
{
t.time++;///杀死守卫多花一个时间单位
}
if(t.time<mintime[a][b])
{
mintime[a][b]=t.time;
q.push(t);
}
}
}
}
return mintime[ax][ay];
}
int main()
{
int i,j,mint;
int sx,sy;
point start;
while(scanf("%d%d",&n,&m)!=EOF)
{
getchar();
memset(maps,,sizeof(maps));
for(i=; i<n; i++)
{
for(j=; j<m; j++)
{
scanf("%c",&maps[i][j]);
mintime[i][j]=INF;
if(maps[i][j]=='a')
{
ax=i;
ay=j;
}
if(maps[i][j]=='r')
{
sx=i;
sy=j;
}
}
getchar();
}
start.x=sx;
start.y=sy;
start.step=;
start.time=;
mintime[sx][sy]=;
mint=BFS(start);
if(mint<INF)
{
printf("%d\n",mint);
}
else
{
printf("Poor ANGEL has to stay in the prison all his life.\n");
}
}
return ;
}
这道题我还看到网上大多数的做法是使用优先队列+BFS,这里我也给出使用优先队列做法的代码与解释
使用优先队列的话,我们需要这样的一个结构体
struct point
{
int x;
int y;
int time;
bool friend operator<(point a,point b)
{
return a.time>b.time;///耗时小的优先
}
};
用time来记录移动和打败守卫的耗时,在优先队列中走到每一个位置状态中耗时少的优先入队,这样就改变了BFS原先的搜索方式了,我们知道,BFS之所以称之为广度优先搜索是因为其搜索方式是如同水波的涟漪一样,从搜索点向四周扩散,可现在的搜索方式是先向四周中耗时最少的点扩散,哪怕到了新的邻点,由于优先队列的机制,只要到新的邻点的时间比到之前邻点少,也会先去搜索新的邻点的邻点,即新的邻点的邻点在队列中的位置在之前的邻点的前面。
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int n,m;
struct point
{
int x;
int y;
int time;
bool friend operator<(point a,point b)
{
return a.time>b.time;///耗时小的优先
}
};
char maps[][];
int vis[][];///标明访问状态的数组
int dix[]= {,-,,};
int diy[]= {,,,-};
int ax,ay;///Angel位置
int judge(int x,int y)///判断能否移动到相邻的位置
{
if(x>=&&x<n&&y>=&&y<m&&maps[x][y]!='#'&&vis[x][y]==)///排除边界,墙和访问状态
{
return ;
}
return ;
}
int BFS(point s)
{
int i,a,b;
priority_queue<point>q;
while(!q.empty())
{
q.pop();
}///清空队列
vis[s.x][s.y]=;
q.push(s);
point hd;
while(!q.empty())
{
hd=q.top();
q.pop();
if(hd.x==ax&&hd.y==ay)
{
return hd.time;
}
for(i=; i<; i++)
{
a=hd.x+dix[i];
b=hd.y+diy[i];
if(judge(a,b))
{
point t;///向第i方向后走一步的位置
t.x=a;
t.y=b;
t.time=hd.time+;
if(maps[a][b]=='x')
{
t.time++;///杀死守卫多花一个时间单位
}
q.push(t);
vis[a][b]=;
}
}
}
return ;
}
int main()
{
int i,j,mint;
int sx,sy;
point start;
while(scanf("%d%d",&n,&m)!=EOF)
{
getchar();
memset(maps,,sizeof(maps));
memset(vis,,sizeof(vis));
for(i=; i<n; i++)
{
for(j=; j<m; j++)
{
scanf("%c",&maps[i][j]);
if(maps[i][j]=='a')
{
ax=i;
ay=j;
}
if(maps[i][j]=='r')
{
sx=i;
sy=j;
}
}
getchar();
}
start.x=sx;
start.y=sy;
start.time=;
mint=BFS(start);
if(mint==)
{
printf("Poor ANGEL has to stay in the prison all his life.\n");
}
else
{
printf("%d\n",mint);
}
}
return ;
}
因为看到数据量并不是很大,这道题我之前也试图使用DFS穷举加上一些剪枝来解决,可是时间超限,不过这次对DFS和BFS也有了一些新的理解了
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
char maps[][];
int vis[][];
int dix[]={,-,,};
int diy[]={,,,-};
int ans;///记录最小耗时
int flag;///记录是否能够找到天使
void my_dfs(int x,int y,int time)///time记录所用的时间
{
int i,a,b;
if(maps[x][y]=='#'||vis[x][y]==)
{
return ;
}
if(time>=ans)///此处为一次剪枝
{
return ;
}
if(maps[x][y]=='r')
{
flag=;
if(time<ans)///找到最短的通路
{
ans=time;
}
return ;
}
if(maps[x][y]=='x')
{
time++;
}
vis[x][y]=;
for(i=;i<;i++)
{
a=x+dix[i];
b=y+diy[i];
my_dfs(a,b,time+);
}
vis[x][y]=;///消去标记
}
int main()
{
int i,j,x,y;
while(scanf("%d%d%",&n,&m)!=EOF)
{
getchar();
memset(maps,'#',sizeof(maps));
memset(vis,,sizeof(vis));
for(i=;i<=n;i++)
{
for(j=;j<=m;j++)
{
scanf("%c",&maps[i][j]);
if(maps[i][j]=='a')
{
x=i;
y=j;
}
}
getchar();
}
flag=;
ans=*;///迷宫规模
my_dfs(x,y,);
if(flag)
{
printf("%d\n",ans);
}
else
{
printf("Poor ANGEL has to stay in the prison all his life.\n");
}
}
return ;
}
Rescue(BFS时间最短 另开数组或优先队列)的更多相关文章
- 解决N个人过桥时间最短问题(Java版本)
[问题描述] n个人要晚上过桥,在任何时候最多两个人一组过桥,每组要有一只手电筒.在这n个人中只有一个手电筒能用,因此要安排以某种往返的方式来返还手电筒,使更多的人可以过桥. 注意:每个人的过桥速 ...
- poj1649 Rescue(BFS+优先队列)
Rescue Time Limit: 2 Seconds Memory Limit: 65536 KB Angel was caught by the MOLIGPY! He was put ...
- HDU1242 Rescue(BFS+优先队列)
Rescue Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
- hdu1242 Rescue(BFS +优先队列 or BFS )
http://acm.hdu.edu.cn/showproblem.php?pid=1242 题意: Angel被传说中神秘的邪恶的Moligpy人抓住了!他被关在一个迷宫中.迷宫的长.宽不超 ...
- 关于bfs时间轴
对于bfs,由于是通过不断将平行位置的元素加入到队列进行的,所以它在一定情况下淡化了与队列外部的 "时间" 联系观念,通过一个数组记录内部的 "时间" 这 ...
- hdu 1242 Rescue (BFS)
Rescue Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
- ZOJ-1649 Rescue BFS (HDU 1242)
看题传送门: ZOJ http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1649 HDU http://acm.hdu.edu. ...
- 线性时间O(n)内求数组中第k大小的数
--本文为博主原创,转载请注明出处 因为最近做的WSN(wireless sensor network)实验要求用3个传感器节点接受2000个包的数据并算出一些统计量,其中就有算出中位数这么一个要求, ...
- hdu1372 BFS求最短路径长度
C - 广搜 基础 Crawling in process... Crawling failed Time Limit:1000MS Memory Limit:65536KB 64bi ...
随机推荐
- shell习题第1题:每日一文件
[题目要求] 请按照这样的日期格式(xxxx-xx-xx)每日生成一个文件 例如生成的文件为2019-04-25.log,并且把磁盘使用情况写入到这个文件中 不用考虑cron,仅仅写脚本即可 [核心要 ...
- md5加密+盐方式二
这类md5+盐加密是属于自定义盐值的简单方法! 1.导入架包 2.调用方法 DigestUtils.md5Hex(password);//加密方法 举例 方式一: password=DigestUti ...
- Python入门 —— 02基础语法
基础语法入门学习推荐: 简明 Python 教程 下文仅为入门推荐书籍的补充与重点 多行语句:末尾使用斜杠 ( ) ,将一行分为多行 var = item1 + item2 + item3 注释: ...
- XSS攻击 && CSRF攻击 基础理解
一个网站,不管多么的帅气,多么的风骚,如果你不安全,那始终都是一个弟弟啊~ 今天又看了下XSS和CSRF攻击的文章,我也想发点什么普及下大家的安全意识,毕竟作为一名拥有伟大梦想的程序员,基本的安全意识 ...
- linux服务器项目部署【完整版】
之前总玩v8虚拟机,最近看到腾讯云学生套餐很实惠就租了个linux服务器搭一个项目,做下这个项目部署全记录,即为了方便以后查看,同时也分享下自己的经验,不足之处还请多多指教,废话不多说,直接开始!!! ...
- Python 爬虫 (四)
requests: 练手 雪qiu网 import requests import json import re import pymysql url = 'https://xueqiu.com/v4 ...
- JavaScript预解析
定义:JavaScript"预解析",可以理解为把变量或函数预先解析到它们被使用的环境中. 通俗点讲,即认为浏览器在正式运行JavaScript代码前, 第一步,会预先根据关键字v ...
- window下创建虚拟环境
一. windows下创建虚拟环境 1. 终端下执行命令:python -m pip install -upgrade pip 2. pip install virtualenv 3. 在本地创建一个 ...
- mongoengine中queryset触发网络访问机制剖析
背景 最近新上线的一个服务,偶尔会有超时告警,其主要逻辑仅仅只是简单的读/写mongodb,而且服务上线初期,流量并不大,因而理论上来说,每次请求都应该很快才对,事实上分析日志也证实90%以上的请求都 ...
- LeetCode: 29. Divide Two Integers (Medium)
1. 原题链接 https://leetcode.com/problems/divide-two-integers/description/ 2. 题目要求 给出被除数dividend和除数divis ...