Nowcodercontest5278 K 迷宫

cnblogs界面

可以说看起来不难写起来真的不简单,还得封装一下

定义表示当前位置是否用过传送,枚举转移,用就能满足转移顺序

可以看到有三种转移形式

对于的两种状态之间用转移

的状态转移

这三种转移形式我们把它们分开三部分,对于的转移,每次取到的区域是一个矩形

定义辅助数组表示第行,范围在范围内的的最小值和出现位置

固定,然后从小到大枚举,是一个标准的单调队列模板

然后固定,从小到大枚举,找到最小的即可

#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<set>
#include<cmath>
#include<cassert>
using namespace std;

#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)

#define pb push_back
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }

char IO;
template<class T=int> T rd(){
    T s=0;
    int f=0;
    while(!isdigit(IO=getchar())) if(IO=='-') f=1;
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return f?-s:s;
}

const int N=2e3+10,INF=1e9+10;

int n,m,d,sx,sy,fx,fy;
char s[N][N];
pair <int,int> pre1[N][N],pre2[N][N],pre3[N][N]; // 记录了转移方案
int dis[N][N];
queue <pair <int,int> > que; // bfs序列
const int z[5][4]={{-1,0},{1,0},{0,1},{0,-1}};

struct Node{
    int x,y,d;
    bool operator < (const Node __) const {
        return d<__.d;
    }
    bool operator > (const Node __) const {
        return d>__.d;
    }
}A[N][N<<1],B[N*N]; //x,y决策位置,d为决策权值
int cnt;
Node Q[N];
int L,R;
int ansx[N*N*2],ansy[N*N*2],ansc;


int main(){
    n=rd(),m=rd(),d=rd();
    rep(i,1,n) scanf("%s",s[i]+1);
    rep(i,1,n) rep(j,1,m) if(s[i][j]=='S') sx=i,sy=j;
    rep(i,1,n) rep(j,1,m) if(s[i][j]=='T') fx=i,fy=j;

    //三步转移
    //Part1
    rep(i,1,n) rep(j,1,m) dis[i][j]=INF;
    que.push(make_pair(sx,sy)),dis[sx][sy]=0;
    while(!que.empty()) {
        int x=que.front().first,y=que.front().second; que.pop();
        rep(i,0,3) {
            int x1=x+z[i][0],y1=y+z[i][1];
            if(dis[x1][y1]==INF && s[x1][y1]!='X') dis[x1][y1]=dis[x][y]+1,pre1[x1][y1]=make_pair(x,y),que.push(make_pair(x1,y1));
        }
    }


    //Part2
    rep(i,1,n) {
        L=1,R=0;
        rep(j,1,m+d) {
            while(L<=R && Q[L].y<j-d*2) ++L;
            if(dis[i][j]<INF && j<=m) {
                Node t=(Node){i,j,dis[i][j]};
                while(L<=R && Q[R]>t) --R;
                Q[++R]=t;
            }
            if(L<=R) A[i][j]=Q[L];
        }
    }
    rep(j,1,m) {
        int ry=j+d,now=0;
        L=1,R=0;
        rep(i,1,n) {
            int lx=max(1,i-d),rx=min(n,i+d);
            while(L<=R && Q[L].x<lx) ++L;
            while(now<rx) {
                ++now;
                if(!A[now][ry].x) continue
                while(L<=R && Q[R]>A[now][ry]) R--;
                Q[++R]=A[now][ry];
            }
            if(s[i][j]!='X' && L<=R && Q[L].x && Q[L].d+1<dis[i][j]) dis[i][j]=Q[L].d+1,pre2[i][j]=make_pair(Q[L].x,Q[L].y);
        }
    }

    //Part3
    rep(i,1,n) rep(j,1,m) B[++cnt]=(Node){i,j,dis[i][j]};
    sort(B+1,B+cnt+1);
    rep(i,1,cnt) que.push(make_pair(B[i].x,B[i].y));
    while(!que.empty()) {
        int x=que.front().first,y=que.front().second; que.pop();
        rep(i,0,3) {
            int x1=x+z[i][0],y1=y+z[i][1];
            if(dis[x1][y1]>dis[x][y]+1 && s[x1][y1]!='X') dis[x1][y1]=dis[x][y]+1,pre3[x1][y1]=make_pair(x,y),que.push(make_pair(x1,y1));
        }
    }

    //输出方案
    if(dis[fx][fy]==INF) return puts("-1"),0;
    int x=fx,y=fy;
    ansx[++ansc]=x,ansy[ansc]=y;
    while(pre3[x][y].first) {
        auto t=pre3[x][y];
        x=t.first,y=t.second;
        ansx[++ansc]=x,ansy[ansc]=y;
    }
    if(pre2[x][y].first) {
        auto t=pre2[x][y];
        x=t.first,y=t.second;
        ansx[++ansc]=x,ansy[ansc]=y;
    }
    while(pre1[x][y].first) {
        auto t=pre1[x][y];
        x=t.first,y=t.second;
        ansx[++ansc]=x,ansy[ansc]=y;
    }
    printf("%d\n",ansc-1);
    drep(i,ansc,1) printf("%d %d\n",ansx[i]-1,ansy[i]-1);
}