2020CCPC(威海) — B Labyrinth(bfs+思维)

B.Labyrinth

题目大意:

给你一个n*m的矩阵,在矩阵内部有k个黑洞(表示不可行走的区域),现在给出q次询问,每次询问给出两个点(x1,y1)和(x2,y2),问从点(x1,y1)到点(x2,y2)的最短路是多少。

思路:

如果每次都从起点和终点-开始考虑bfs寻找最短路的话,那么这样的数据范围肯定会超时的。但是黑洞的范围很小,显然我们应该从黑洞入手考虑。
1.如果矩形区域【x1,x2】X【y1,y2】没有黑洞,那么两点之间的最短距离必为曼哈顿距离。
2.否则一定存在一条最短路,经过黑洞的上下左右四个点之一。那么由于黑洞的数量很少,我们可以以黑洞的上下左右四个点作为中间点。用bfs进行预处理,然后对于每个查询来说就是枚举中间点维护最短距离就好了。

但需要注意的是,如果记录距离时四维数组开满的话肯定会炸,所以我们用new的方法来动态开内存

AC Code

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf=1e9;
const int N=2e5+10;
set<pair<int,int>>ans;
map<pair<int,int>,int>mp;
int n,m,k,q;
int *dis[45][4][N];
int dir[4][2]={
    
    {
    
    0,-1},{
    
    0,1},{
    
    1,0},{
    
    -1,0}};//黑洞的上下左右四个方向
struct node
{
    
    
    int x,y;
    int dist;
};
void bfs()
{
    
    
    for(auto iter=ans.begin();iter!=ans.end();iter++)
    {
    
    //遍历每个黑洞
        int x=(*iter).first;        //黑洞的坐标
        int y=(*iter).second;
        int idx=mp[make_pair(x,y)]; //黑洞的编号
        for(int i=0;i<4;i++)
        {
    
    //遍历该黑洞的4个方向
            int dx=x+dir[i][0];
            int dy=y+dir[i][1];
            if(dx<1||dx>n||dy<1||dy>m) continue; //越界
            if(ans.count(make_pair(dx,dy))) continue; //如果这个点也是黑洞
            for(int j=1;j<=n;j++)
            {
    
    
                dis[idx][i][j]=new int[m+5];
                for(int k=1;k<=m;k++)
                    dis[idx][i][j][k]=inf;
            }
            dis[idx][i][dx][dy]=0;
            queue<node>que;
            node p;
            p.x=dx,p.y=dy,p.dist=0;
            que.push(p);
            while(!que.empty())
            {
    
    
                node now=que.front();
                que.pop();
                for(int j=0;j<4;j++)
                {
    
    
                    int fx=now.x+dir[j][0];
                    int fy=now.y+dir[j][1];
                    if(fx<1||fx>n||fy<1||fy>m) continue;
                    if(dis[idx][i][fx][fy]!=inf) continue;
                    if(ans.count(make_pair(fx,fy))) continue;
                    dis[idx][i][fx][fy]=now.dist+1;
                    que.push({
    
    fx,fy,dis[idx][i][fx][fy]});
                }
            }
        }
    }
}
bool check(int x1,int y1,int x2,int y2)
{
    
    
    if(x1>x2) swap(x1,x2);
    if(y1>y2) swap(y1,y2);
    for(auto iter=ans.begin();iter!=ans.end();iter++)
    {
    
    
        int dx=(*iter).first;
        int dy=(*iter).second;
        if(dx>=x1&&dx<=x2&&dy>=y1&&dy<=y2)//矩形范围内存在黑洞
            return false;
    }
    return true;
}
int main()
{
    
    
    scanf("%d%d%d%d",&n,&m,&k,&q);
    for(int i=1;i<=k;i++)
    {
    
    
        int x,y;
        scanf("%d%d",&x,&y);
        ans.emplace(x,y);   //将黑洞以pair的形式存入set中
        mp[make_pair(x,y)]=i;//将每个黑洞编号
    }
    bfs();
    while(q--)
    {
    
    
        int xs,ys,xt,yt;
        scanf("%d%d%d%d",&xs,&ys,&xt,&yt);  //输入起点和终点
        //如果区域中没有黑洞,那么返回曼哈顿距离
        if(check(xs,ys,xt,yt)) printf("%d\n",abs(xs-xt)+abs(ys-yt));
        else
        {
    
    
            int res=inf;
            for(auto iter=ans.begin();iter!=ans.end();iter++)//遍历每个黑洞
            {
    
    
                int x=(*iter).first;
                int y=(*iter).second;
                int idx=mp[make_pair(x,y)];//黑洞的编号
                for(int i=0;i<4;i++)
                {
    
    
                    int dx=x+dir[i][0];
                    int dy=y+dir[i][1];
                    if(dx>n||dx<1||dy>m||dy<1) continue; //越界
                    if(ans.count(make_pair(dx,dy))) continue; //如果查询的点也是黑洞
                    res=min(res,dis[idx][i][xs][ys]+dis[idx][i][xt][yt]);
                }
            }
            if(res==inf) printf("-1\n");
            else printf("%d\n",res);
        }
    } 
    //system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Stevenwuxu/article/details/113031989