Description
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.)
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.)
Input
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.
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
样例1:
#include <stdio.h>
#include <string.h>
#define Min(A,B) ((A<B)? A:B)
struct Team
{
int x,y,s;
}que[40010]; //定义Bfs使用的结构体.模拟队列
int p,q,m,n,min=99999;
char map[202][202]; //记录地图
int visit[202][202]; //标记地图
int a[4][2]={0,1,0,-1,1,0,-1,0}; //方向数组
void bfs(int x,int y) //定义Bfs函数旨在找到当前点到天使的最短路程
{
int head,tail,tx,ty,i,book=0;
head=tail=0;
que[tail].x=x;
que[tail].y=y;
que[tail++].s=0;
while(head<tail)
{
if(que[head].s==min)
break;
if(map[que[head].x][que[head].y]=='@') //找到@表示这个是x杀死后.
{
visit[que[head].x][que[head].y]=1; //杀死后就记录该点已经走过
map[que[head].x][que[head].y]='.'; //把该点变为普通点
que[tail].x=que[head].x;
que[tail].y=que[head].y;
que[tail++].s=que[head].s+1; //该点坐标不变步数加1继续加到队尾
head++; //注意这里要加上.因为后面的continue会跳过head++.
continue;
}
for(i=0;i<4;i++) //循环四个方向进行拓展
{
tx=que[head].x+a[i][0];
ty=que[head].y+a[i][1];
if(tx<0||tx>=n||ty<0||ty>=m) //边界判断
continue;
if(map[tx][ty]=='#'||visit[tx][ty]==1) //判断这个点是否走过或者是#
continue;
if(map[tx][ty]=='a') //如果找到天使就book=1。
{
book=1;
break;
}
if(map[tx][ty]=='r') //如果找到了天使的伙伴,那么说明这条路肯定不是最短的,因为可以直接由这个天使的伙伴直接走.
{
visit[tx][ty]=1;
continue;
}
if(map[tx][ty]=='.') //普通的路就直接加入队列,标记该点走过.
{
visit[tx][ty]=1;
que[tail].x=tx;
que[tail].y=ty;
que[tail++].s=que[head].s+1;
}
if(map[tx][ty]=='x') //遇到警卫,该点标记为特殊的@,将该点加入到队列中
{
map[tx][ty]='@';
que[tail].x=tx;
que[tail].y=ty;
que[tail++].s=que[head].s+1;
}
}
if(book==1)
break;
head++; //拓展的关键.
}
if(book==1)
min=Min(min,que[head].s+1); //如果找到天使就更新最小值
}
int main()
{
int i,j;
while(~scanf("%d%d",&n,&m))
{
min=99999;
for(i=0;i<n;i++)
scanf("%s",map[i]);
for(i=0;i<n;i++)
for(j=0;j<m;j++)
if(map[i][j]=='r') //循环找天使的伙伴进入Bfs.
{
memset(visit,0,40000*sizeof(int));
visit[i][j]=1;
bfs(i,j);
}
if(min!=99999)
printf("%d\n",min);
else
printf("Poor ANGEL has to stay in the prison all his life.\n");
}
return 0;
}
样例2:
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
struct node
{
int x, y;
int step;
}s, e;
char map[201][201];
int visit[201][201];
int A,B,prove;
int ex,ey,tx,ty;
int v=50000; //最小值
int d[4][2]={0,1,1,0,-1,0,0,-1};
void BFS(int x, int y)
{
queue<node>q; //定义node类型的队列
s.x = x;
s.y = y;
s.step = 0;
q.push(s); //把初始点(天使的位置)加到队列的开头.
map[s.x][s.y] = '#'; //把初始点设为墙
int i;
while(!q.empty()) //如果队列长度不为0进入循环
{
s = q.front(); //取出队头的元素放在s中
q.pop(); //删除队头元素
if(map[s.x][s.y]=='r') //(逆向寻找)如果找到天使的伙伴就输出当前步数并且标记prove为1.
{
printf("%d\n",s.step);
prove=1;
break;
}
if(map[s.x][s.y]=='@') //作用同样例1
{
s.step++;
map[s.x][s.y]='#';
q.push(s);
continue;
}
for(i = 0; i < 4; i++) //四个方向上拓展
{
e.x = s.x + d[i][0];
e.y = s.y + d[i][1];
if(e.x>=0&&e.x<A&&e.y>=0&&e.y<B)
{
if(map[e.x][e.y]=='r')
{
e.step=s.step+1;
q.push(e);
}
if(map[e.x][e.y]=='.')
{
e.step=s.step+1;
map[e.x][e.y] ='#';
q.push(e);
}
if(map[e.x][e.y]=='x')
{
e.step=s.step+1;
map[e.x][e.y] ='@';
q.push(e);
}
}
}
}
}
int main()
{
int i, j;
while(scanf("%d%d", &A, &B)!=EOF)
{
getchar();
for(i = 0; i < A; i++)
{
for(j = 0; j< B; j++)
{
scanf("%c", &map[i][j]);
if(map[i][j]=='a') //(逆向查找)以天使的位置为起点
{
map[i][j]='.';
tx=i;
ty=j;
}
}
getchar();
}
prove = 0;
BFS(tx,ty);
if(prove==0)
printf("Poor ANGEL has to stay in the prison all his life.\n");
}
return 0;
}
思路:
这道题有两个地方需要回味:
1.由于这道题是多起点问题,就是说有很多天使的朋友,都可以出发去救天使.然后找出最短的途径.所以样例1中,循环找天使的伙伴然后找到每个天使伙伴的最短路径之后再找最短.
但是样例2中逆向思维,以天使为起点,问题就转化为天使找他的伙伴.那么用bfs搜素的话,第一个找到的伙伴之间的路程一定是最短的.
2.对于警卫的问题,如果直接步数加2.那么队列的步数就不是一致性的了,换句话说第一次到达目标点的不一定是最短路程.
假如拓展方向是先左边后右边,那么左边拓展始终在右边拓展前面.意思就是程序是左边拓展途径先到E.但是实际上是右边最短.
这个问题可以使用优先队列来,但是以上两个样例的处理方法也很巧妙.