洛谷 P2199 最后的迷宫

 

 

 

这道题作为一道广度优先搜索的题目,和其他的写法没有太大不同,但是有很多坑~,(多踩几次就填上了)

1.在这道题中,哈利可以只要与奖杯在题目所描述的八个方向上能够直接通往奖杯(也就是说不能有墙),那么就可以结束搜索,次数也可以不用加一。

2.这道题要重复输入多遍哈利和奖杯的坐标,而且是先输入奖杯,在输入哈利坐标(坑!),所以可以使用一个数组先记录下来,然后每一遍都进行初始化

3.再就是奖杯一开始就在哈利的手中(奖杯坐标与哈利坐标重合),需要特判

4.这道题不能只用一个数组来记录不能走到的点,因为如果在搜索的过程中只用一个数组进行记录,就会导致走过的点和本身是墙的点都变成一个不能走的点,但是在最后判断能否直接拿到的时候并不能考虑走过的点,所以需要用两个数组进行记录,一个记录墙壁,一个记录已走过的点,避免混乱

源代码:

#include<iostream>
#include<cstdio>
#include<math.h>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;

struct STU
{
    int xx;
    int yy;
};

queue<STU> q;
int go[5][2]={{0,0},{1,0},{-1,0},{0,1},{0,-1}};
int val[1600][1600];
int mapp1[1600][1600];//记录墙壁坐标
int mapp2[1600][1600];//记录已走点坐标
int step[1600][1600];
int flag,n,m,ex,ey,bx,by,tx,ty,qx,qy,ans;
char a;

int win(int x,int y)//判断可不可以用“飞来咒”直接拿到奖杯
{
    if(x==ex&&y==ey)//奖杯和哈利重合
    {
        return 1;
    }    
    
    if(x==ex)//在同一水平直线上
    {    
        for(int i=min(y,ey);i<=max(y,ey);i++)
        {
            if(mapp1[x][i]==1) return 0;
        }
        
        return 1;
    }
    if(y==ey)//在同一竖直直线上
    {
        for(int i=min(x,ex);i<=max(x,ex);i++)
        {
            if(mapp1[i][y]==1) return 0;
            
        }
        return 1;
    }
    if(x-y==ex-ey)//在同一方向为东北——西南的直线上
    {
        for(int i=1;i<=abs(ex-x);i++)
        {
            if(x<ex)
            {
                if(mapp1[x+i][y+i]==1) return 0;
            }
            else
            {
                if(mapp1[x-i][y-i]==1) return 0;
            }
        }
        
        return 1;
    }    
    if(x+y==ex+ey)//在同一方向为西北——东南的直线上
    {
        for(int i=1;i<=abs(x-ex);i++)
        {
            if(x<ex)
            {
                if(mapp1[x+i][y-i]==1) return 0;
            }
            else
            {
                if(mapp1[x-i][y+i]==1) return 0;
            }
        }
        
        return 1;
    }
    
    return 0;//啥都不符合。。。
}

int bfs(int x,int y)//正常广度优先搜索
{
    q.push((STU){x,y});
    mapp2[x][y]=1;
    step[x][y]=0;
    
    while(q.size()!=0)
    {
        qx=q.front().xx;
        qy=q.front().yy;
        q.pop();
        
        if(win(qx,qy)==1)//能拿到就结束
        {
            return step[qx][qy];
        }
        
        for(int i=1;i<=4;i++)
        {
            tx=qx+go[i][0];
            ty=qy+go[i][1];
            
            if(tx<1||ty<1||tx>n||ty>m||mapp2[tx][ty]==1)
            {
                continue;
            }
            
            mapp2[tx][ty]=1;
            step[tx][ty]=step[qx][qy]+1;
            q.push((STU){tx,ty});
        }
    }
    
    return -1;//拿不到打个标记
}

int main(void)
{
    scanf("%d%d",&n,&m);
    
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>a;
            
            if(a=='X') val[i][j]=1;//标记墙壁,之后每一遍输入均可使用
        }
    }
    
    for( ; ; )
    {
        scanf("%d%d%d%d",&ex,&ey,&bx,&by);
        
        if(bx==0&&by==0&&ex==0&&ey==0)
        {
            break;
        }
        
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                mapp2[i][j]=mapp1[i][j]=val[i][j];//走过的也把墙壁标记为已走路径,不再经过
            }
        }
        
        ans=bfs(bx,by);
        
        if(ans==-1)
        {
            printf("Poor Harry\n");
        }
        else
        {
            printf("%d\n",ans);
        }
        
        memset(step,0,sizeof(step));//切记初始化
        memset(mapp1,0,sizeof(mapp1));
        memset(mapp2,0,sizeof(mapp2));
        
        while(q.size()!=0)//队列初始化
        {
            q.pop();
        }
    }
    
    return 0;
}

 

posted @ 2020-05-17 15:25  雾隐  阅读(272)  评论(0编辑  收藏  举报