C语言BFS(2)___Rescue

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.) 
 

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. 
 

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.但是实际上是右边最短.


这个问题可以使用优先队列来,但是以上两个样例的处理方法也很巧妙.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值