• [双端BFS][二维单调队列] 2020科大讯飞杯上海大学友谊赛 K.迷宫


    题目链接

    Solution

    传送操作最多使用一次,所以可以从起点和终点分别开始BFS,然后枚举点对进行传送。因为可以传送的点对要满足切比雪夫距离小于等于d,实际上就是一个((d+1) imes (d+1))的子矩阵内的点对可以互相传送,这个东西可以用二维单调队列来维护。找到使得路程最小的传送的两个点后,输出路径即可。

    Code

    #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
    ",Res);
        for(RG i=RouteA.size()-1;i>=0;--i)
            printf("%d %d
    ",RouteA[i].x-1,RouteA[i].y-1);
        for(RG i=0;i<RouteB.size();++i)
            printf("%d %d
    ",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
    ");
            printf("%d %d
    %d %d
    ",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
    ");return 0;}
        RouteA.reserve(LenA+5);
        RouteB.reserve(LenB+5);
        Solve();
        return 0;
    }
    
  • 相关阅读:
    Entity Framework 6 (7) vs NHibernate 4: DDD perspective(纯净DDD很难很难...)
    asp.net解决高并发的方案
    我所经历的SAP选型[转]
    为什么我不再用 .NET 框架
    Why I Left the .NET Framework
    Docker 传奇之 dotCloud
    ICE概述
    .NET Out Of Memory Exception
    iOS-申请邓白氏编码的超详细流程介绍
    .NET对象与Windows句柄(三):句柄泄露实例分析
  • 原文地址:https://www.cnblogs.com/AEMShana/p/12731480.html
Copyright © 2020-2023  润新知