题目背景:
哈利•波特作为三强争霸赛的第四名选手,历尽艰险闯到了最后一关——迷宫。
现在,迷宫里只剩下哈利和塞德里克了,哈利只有在塞德里克前面拿到奖杯,才能赢得比赛。哈利只要能看到奖杯,就可以用飞来咒拿到它,所以,现在的问题是哈利如何能尽早地看到奖杯。
题目描述:
哈利的视力非常好,他能从迷宫的一端沿直线看到迷宫的另一端(但他只能看八个方向——东北,东,东南,南,西南……),而且跑得非常快,跑一步(向上、下、左、右移动一格)只需要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;
}