• Nowcodercontest5278 K 迷宫


    Nowcodercontest5278 K 迷宫

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

    \(O(n^2m^2)\)

    \(dp[i][j][k]\)定义表示当前位置\((i,j)\)\(k\)是否用过传送,枚举\(O(d^2)\)转移,用\(\text{BFS}\)就能满足转移顺序

    \(O(nm)\)

    可以看到有三种转移形式

    对于\(k=0,k=1\)的两种\(dp\)状态之间用\(\text{BFS}\)转移

    \(k=0\rightarrow k=1\)的状态转移

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

    定义辅助数组\(A[i][j]\)表示第\(i\)行,范围在\([j-2d,j]\)范围内的\(dp[i][j][0]\)的最小值和出现位置

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

    然后固定\(j\),从小到大枚举\(i\),找到\(k\in[i-d,i+d]\)最小的\(A[k][j+d]\)即可

    #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);
    }
    
  • 相关阅读:
    XXX系统讨论
    问题账户需求分析
    2017年秋季个人阅读计划
    《软件工程概论》的评价
    第二阶段Day10
    每周总结16
    假期学习记录13(ImageView实现动态加载网络图片)
    假期学习记录12(android与web服务器之间的list/json数组的消息传递)
    假期学习记录11(NavigationView点击事件无效)
    假期学习记录10(自定义AlertDialog,按钮关闭AlertDialog)
  • 原文地址:https://www.cnblogs.com/chasedeath/p/12727496.html
Copyright © 2020-2023  润新知