[BFS de doble extremo] [Cola monótona bidimensional] 2020 HKUST Xunfei Cup Shanghai University Friendship K. Labyrinth

Enlace del título

Solución

La operación de transferencia se usa como máximo una vez, por lo que puede iniciar BFS desde el punto inicial y el punto final respectivamente, y luego enumerar los pares de puntos para transferir. Debido a que los pares de puntos que pueden transmitirse deben satisfacer la distancia de Chebyshev menor o igual que d, de hecho , los pares de puntos en una submatriz de \ ((d + 1) \ times (d + 1) \) pueden transmitirse entre sí. Use una cola monótona bidimensional para mantener. Después de encontrar los dos puntos de transmisión que minimizan la distancia, la ruta de salida es suficiente.

Código

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <vector>
using namespace std;

#define RG register int
#define LL long long

struct node{int x,y;};
struct Node{int x,y,Step;};
queue<Node> Q;
Node DataA[2005][2005],DataB[2005][2005];
char G[2005][2005];
int visA[2005][2005],visB[2005][2005];
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
vector<node> RouteA,RouteB;
int N,M,T,Stx,Sty,Edx,Edy,Ax,Ay,Bx,By,Ans=2147483647;

void BFSA(){
    memset(visA,0x3f,sizeof(visA));
    while(!Q.empty()) Q.pop();
    Q.push((Node){Stx,Sty,0});visA[Stx][Sty]=0;
    DataA[Stx][Sty]=(Node){Stx,Sty,0};
    while(!Q.empty()){
        Node Cur=Q.front();Q.pop();
        for(RG i=0;i<4;++i){
            int Nx=Cur.x+dx[i],Ny=Cur.y+dy[i];
            if(G[Nx][Ny]=='X') continue;
            if(visA[Nx][Ny]<100000000) continue;
            if(Nx<1||Nx>N||Ny<1||Ny>M) continue;
            visA[Nx][Ny]=Cur.Step+1;
            Q.push((Node){Nx,Ny,Cur.Step+1});
            DataA[Nx][Ny]=Cur;
        }
    }
    return;
}

void BFSB(){
    memset(visB,0x3f,sizeof(visB));
    while(!Q.empty()) Q.pop();
    Q.push((Node){Edx,Edy,0});visB[Edx][Edy]=0;
    DataB[Edx][Edy]=(Node){Edx,Edy,0};
    while(!Q.empty()){
        Node Cur=Q.front();Q.pop();
        for(RG i=0;i<4;++i){
            int Nx=Cur.x+dx[i],Ny=Cur.y+dy[i];
            if(G[Nx][Ny]=='X') continue;
            if(visB[Nx][Ny]<100000000) continue;
            if(Nx<1||Nx>N||Ny<1||Ny>M) continue;
            visB[Nx][Ny]=Cur.Step+1;
            Q.push((Node){Nx,Ny,Cur.Step+1});
            DataB[Nx][Ny]=Cur;
        }
    }
    return;
}

template<typename elemType,typename CMP>
struct MPQueue{
    CMP cmp;
    int Pos[2010];
    elemType Node[2010];
    int head,tail,limit;//limit-滑动窗口长度
    MPQueue():head(1),tail(0),limit(1){}
    MPQueue(int _limit):head(1),tail(0),limit(_limit){}
    
    bool size(){return tail-head+1;}
    bool empty(){return tail<head;}//是否为空
    elemType front_elem(){return Node[head];}//获取队首的元素
    int front_pos(){return Pos[head];}//获取队首元素在原序列中的位置
    //以上操作使用前应保证先pop_front队首的过时元素

    void set_limit(int _limit){limit=_limit;}//设置滑动窗口长度
    void clear(){head=1,tail=0;}//清空单调队列
    void push(int pos,elemType elem){//插入元素,维护最小值
        //pos-元素在原序列中的位置,elem-要插入的元素,limit-滑动窗口的长度
        while(head<=tail && (!cmp(Node[tail],elem) || pos-Pos[tail]+1>limit))
            --tail;
        ++tail;Node[tail]=elem;Pos[tail]=pos;
    }
    void pop_front(int pos){//处理过时的队首元素
        while(head<=tail && pos-Pos[head]>=limit) ++head;
    }
};

template<typename elemType,typename CMP>
struct MPQueue2D{//二维单调队列
    struct NODE{int posy;elemType Value;};
    struct CMP2{bool operator()(const NODE &A,const NODE &B)const {
        return CMP()(A.Value,B.Value);}
    };
    MPQueue<elemType,CMP> Row[2010];
    MPQueue<NODE,CMP2> Col;
    int x[2010][2010],y[2010][2010];//x[i][j]-以(i,j)为右下角的子矩阵中最值的行号
                                    //y[i][j]-以(i,j)为右下角的子矩阵中最值的列号
    elemType val[2010][2010],Data[2010][2010];
    //val[i][j]-以(i,j)为右下角的子矩阵中的最值
    //Data-二维单调队列的数据源
    int N,M,limitR,limitC;
    //N-行数,M-列数,limitR-滑动的子矩阵的行数,limitC-滑动的子矩阵的列数
    
    MPQueue2D(int _N=0,int _M=0,int _limitR=0,int _limitC=0):
        N(_N),M(_M),limitR(_limitR),limitC(_limitC) {}
    void setN(int _N){N=_N;}
    void setM(int _M){M=_M;}
    void clear(){
        for(RG i=1;i<=N;++i)
            Row[i].clear();
        Col.clear();
    }
    void set_limit(int _limitR,int _limitC){//设置滑动子矩阵的行数limitR和列数limitC
        limitR=min(_limitR,N);limitC=min(_limitC,M);
        for(RG i=1;i<=N;++i)
            Row[i].set_limit(limitC);
        Col.set_limit(limitR);
    }
    void Query(){//查询二维数组中每个滑动子矩阵的最值及其位置
        for(RG j=1;j<=M;++j){
            Col.clear();//维护列的单调队列
            for(RG i=1;i<=N;++i){
                Row[i].push(j,Data[i][j]);
                Row[i].pop_front(j);
                Col.push(i,(NODE){Row[i].front_pos(),Row[i].front_elem()});
                Col.pop_front(i);
                x[i][j]=Col.front_pos();//以(i,j)为右下角的子矩阵中最值的行号
                y[i][j]=Col.front_elem().posy;//以(i,j)为右下角的子矩阵中最值的列号
                val[i][j]=Col.front_elem().Value;//以(i,j)为右下角的子矩阵中的最值
            }
        }
    }
};

MPQueue2D<int,less<int> > Q1,Q2;

inline void Solve(){
    int px=Ax,py=Ay;
    RouteA.push_back((node){px,py});
    while(!(px==Stx && py==Sty)){
        int x=DataA[px][py].x,y=DataA[px][py].y;
        px=x;py=y;RouteA.push_back((node){px,py});
    }
    px=Bx,py=By;
    if(!(Bx==Ax && By==Ay))
        RouteB.push_back((node){px,py});
    
    while(!(px==Edx && py==Edy)){
        int x=DataB[px][py].x,y=DataB[px][py].y;
        px=x;py=y;RouteB.push_back((node){px,py});
    }
    int Res=RouteA.size()+RouteB.size()-1;
    printf("%d\n",Res);
    for(RG i=RouteA.size()-1;i>=0;--i)
        printf("%d %d\n",RouteA[i].x-1,RouteA[i].y-1);
    for(RG i=0;i<RouteB.size();++i)
        printf("%d %d\n",RouteB[i].x-1,RouteB[i].y-1);
    return;
}

int main(){
    scanf("%d%d%d",&N,&M,&T);
    for(RG i=1;i<=N;++i){
        scanf("%s",G[i]+1);
        for(RG j=1;j<=M;++j){
            if(G[i][j]=='S'){Stx=i;Sty=j;}
            if(G[i][j]=='T'){Edx=i;Edy=j;}
        }
    }
    if(max(abs(Edx-Stx),abs(Edy-Sty))<=T){
        printf("1\n");
        printf("%d %d\n%d %d\n",Stx-1,Sty-1,Edx-1,Edy-1);
        return 0;
    }
    BFSA();BFSB();
    Q1.N=Q2.N=N;Q1.M=Q2.M=M;
    Q1.set_limit(T+1,T+1);Q2.set_limit(T+1,T+1);
    for(RG i=1;i<=N;++i){
        for(RG j=1;j<=M;++j){
            Q1.Data[i][j]=visA[i][j];
            Q2.Data[i][j]=visB[i][j];
        }
    }
    Q1.Query();Q2.Query();
    int LenA=0,LenB=0;
    for(RG i=1;i<=N;++i){
        for(RG j=1;j<=M;++j){
            if(Q1.val[i][j]+Q2.val[i][j]+1<Ans){
                Ans=Q1.val[i][j]+Q2.val[i][j]+1;
                Ax=Q1.x[i][j];Ay=Q1.y[i][j];
                Bx=Q2.x[i][j];By=Q2.y[i][j];
                LenA=Q1.val[i][j];LenB=Q2.val[i][j];
            }
        }
    }
    if(Ans>10000000){printf("-1\n");return 0;}
    RouteA.reserve(LenA+5);
    RouteB.reserve(LenB+5);
    Solve();
    return 0;
}

Supongo que te gusta

Origin www.cnblogs.com/AEMShana/p/12731480.html
Recomendado
Clasificación