洛谷P2199-最后的迷宫(BFS)

题目背景:

哈利•波特作为三强争霸赛的第四名选手,历尽艰险闯到了最后一关——迷宫。

现在,迷宫里只剩下哈利和塞德里克了,哈利只有在塞德里克前面拿到奖杯,才能赢得比赛。哈利只要能看到奖杯,就可以用飞来咒拿到它,所以,现在的问题是哈利如何能尽早地看到奖杯。

题目描述:

哈利的视力非常好,他能从迷宫的一端沿直线看到迷宫的另一端(但他只能看八个方向——东北,东,东南,南,西南……),而且跑得非常快,跑一步(向上、下、左、右移动一格)只需要1s。但迷宫是不透光的,而且,要烧掉迷宫的墙也不容易,所以哈利决定绕到一个能够看到奖杯的地方。现在,哈利希望你能帮他确定最短需要多长时间才能拿到奖杯。

输入格式:

第一行为2个数N,M表示迷宫的规模(N为高,M为宽)

接下来是N*M的迷宫,O表示空地,X表示墙。

最后是多对数据,分别是奖杯坐标及哈利的坐标(显然不可能在墙上),每对占一行,0为结束标志。

输出格式:

根据每对数据,计算哈利拿到奖杯的最短时间,每对一行。如果魔法部有意难为选手,用墙将奖杯包围了起来,输出”Poor Harry”。

样例输入: 

3 4

OXXO

XXOO

XOOO

3 2 2 4

3 3 1 1

0 0 0 0  

样例输出: 

1

Poor Harry  

说明/提示:

对于30%的数据,有N*M<=100

对于60%的数据,有N*M<=1600

对于100%的数据,有N*m<=16384

AC Code:

#include<bits/stdc++.h>
using namespace std;
#define N 2020
int n,m,sx,sy,ex,ey,head,tail,flag;
char s[N][N];//存入地图 
int g[N][N],a[N];//g数组用来枚举奖杯在哪些点可以被看到,a数组是拿到奖杯的时间 
bool vis[N][N];//标记数组 
int dx[]={0,0,1,-1,-1,-1,1,1};//两个方向数组 
int dy[]={1,-1,0,0,-1,1,-1,1};//人可以向4个方向行走,但可以看到周围的8个方向 
struct node {
	int x,y;
}q[N*N];//模拟队列 
int main() {
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++) {
		for(int j=1;j<=m;j++) {
			scanf(" %c",&s[i][j]);//%前面的空格确保地图可以完整输入 
			if(s[i][j]=='X') {//如果这个点是墙 
				g[i][j]=-1;//标记为-1 
			}
		}
	}
	while(~scanf("%d %d %d %d",&ex,&ey,&sx,&sy)) {
		if(ex==0&&ey==0&&sx==0&&sy==0) {//结束标志 
			break;
		}
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=m;j++) {
				if(g[i][j]!=-1) {//如果这个点不是墙 
					g[i][j]=0;//我们暂且将该点记作0 
				}
			}
		}
		flag=0;//标记变量 
		memset(vis,false,sizeof(vis));//清空标记数组 
		g[ex][ey]=1;//奖杯所在的位置修改为1 
		for(int i=0;i<8;i++) {//奖杯可以在8个方向被看到 
			//这里的j没有限制,因为如果某一行或者某一列没有墙,则走到该行(列)自然就可以看到奖杯 
			for(int j=1;;j++) {
				int tx=ex+dx[i]*j;
				int ty=ey+dy[i]*j;
				if(tx<1||tx>n||ty<1||ty>m||g[tx][ty]==-1) {//越界或者该点是墙 
					break;//直接退出 
				}else {
					g[tx][ty]=1;//把奖杯可以被看到的地方都修改为1 
				}
			}
		}
		head=tail=1;//队头队尾初始化 
		vis[sx][sy]=true;//标记人的起点 
		q[head].x=sx;//入队 
		q[head].y=sy;
		tail++;//队尾向后移动一格 
		while(head<tail) {
			if(g[q[head].x][q[head].y]==1) {//只要到达了能看到奖杯的地方,就意味着拿到了奖杯 
				printf("%d\n",a[head]);//输出花费的时间 
				flag=1;//修改标记变量 
				break;
			}
			for(int i=0;i<4;i++) {//人只能向上下左右4个方向移动 
				int nx=q[head].x+dx[i];
				int ny=q[head].y+dy[i];
				//不越界,这个点没有走过,且这个点也不是墙 
				if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&vis[nx][ny]==false&&g[nx][ny]!=-1) {
					vis[nx][ny]=true;//标记这个点 
					q[tail].x=nx;//该点入队 
					q[tail].y=ny;
					a[tail]=a[head]+1;//时间+1 
					tail++;//队尾相应的向后移动一格 
				}
			}
			head++;//队头向后移动一格,继续搜索下一个点 
		}
		if(!flag) {//如果看不到奖杯 
			printf("Poor Harry\n");
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43823808/article/details/107487987