“科大讯飞杯”第18届上海大学程序设计联赛春季赛暨高校网络友谊赛 迷宫(二维最值)

https://ac.nowcoder.com/acm/contest/5278/K

题意:

给一个nm矩阵,上下左右走,求从s到t的最少时间。
有一次机会一步从 ( i , j ) (i,j) 走到 ( [ i d , i d ] , [ j d , j + d ] ) ([i-d,i-d],[j-d,j+d]) ,花费时间也是1。
要求给出路径

解析:

跑一遍从s到每个点的最短路,从每个点到t的最短路。

接下来就是对于每个点,求矩阵范围内的最小值。

由于矩阵的大小均为 ( 1 + 2 d ) ( 1 + 2 d ) (1+2d)(1+2d) ,所以可以线性处理。
从横着处理一遍,对于每个点 ( i , j ) (i,j) ,求出 ( i , j 1 2 d ) (i,j-1-2d) ( i , j ) (i,j) 的最小值。(单调栈)

然后竖着处理,对于每个点,得到左上角的矩阵的最小值。

代码:

/*
 *  Author : Jk_Chen
 *    Date : 2020-04-18-12.52.13
 */
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair<int, int>
#define fi first
#define se second
void test(){cerr<<"\n";}
template<typename T,typename... Args>void test(T x,Args... args){cerr<<x<<" ";test(args...);}
const LL mod=1e9+7;
const int maxn=1e5+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
    while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans; return ans;
}
#define rd rd()
/*_________________________________________________________begin*/
int n,m,d;
char Map[4009][4009];

pill link1[2009][2009];
pill link2[2009][2009];

int dis1[4009][4009];
const int di[4][2]={1,0,0,-1,0,1,-1,0};
void bfs(pill st,int dis[][4009],pill link[][2009]){
    rep(i,1,n)rep(j,1,m)dis[i][j]=inf;
    dis[st.fi][st.se]=0;
    queue<pill>Q;
    Q.push({st.fi,st.se});
    while(!Q.empty()){
        pill P=Q.front();Q.pop();
//        test(P.fi,P.se,dis[P.fi][P.se]);
        rep(i,0,3){
            int x=P.fi+di[i][0];
            int y=P.se+di[i][1];
            if(x<1||x>n||y<1||y>m||Map[x][y]=='X')continue;
            if(dis[x][y]>dis[P.fi][P.se]+1){
                dis[x][y]=dis[P.fi][P.se]+1;
                link[x][y]=P;
                Q.push({x,y});
            }
        }
    }
}

namespace DoubleFind{
    int n,m,d;
    int val[4009][4009];
    int Min[4009][4009];
    pill Ans[4009][4009];
    void init(){
        int len=1+2*d;
        rep(i,1,n){
            deque<int>Q;
            int r=0;
            int l=0-len+1;
            while(r<m+d){
                if(!Q.empty()&&Q.front()==l)Q.pop_front();
                l++;
                r++;
                if(r<=m){
                    while(!Q.empty()&&val[i][r]<=val[i][Q.back()])
                        Q.pop_back();
                    Q.push_back(r);
                }
                Min[i][r]=Q.front();
            }
        }
        rep(j,1,m+d){
            deque<int>Q;
            int r=0;
            int l=0-len+1;
            while(r<n+d){
                if(!Q.empty()&&Q.front()==l)Q.pop_front();
                l++;
                r++;
                if(r<=n){
                    while(!Q.empty()&&val[r][Min[r][j]]<=val[Q.front()][Min[Q.front()][j]])Q.pop_back();
                    Q.push_back(r);
                }
                Ans[r][j]={Q.front(),Min[Q.front()][j]};
            }
        }
    }
    int Findval(int xmax,int ymax){
        return val[Ans[xmax][ymax].fi][Ans[xmax][ymax].se];
    }
}

int main(){
    pill s,t;
    scanf("%d%d%d",&n,&m,&d);
    DoubleFind::n=n;
    DoubleFind::m=m;
    DoubleFind::d=d;

    rep(i,1,n){
        scanf("%s",Map[i]+1);
        rep(j,1,m){
            if(Map[i][j]=='S')s={i,j};
            if(Map[i][j]=='T')t={i,j};
        }
    }
    bfs(s,dis1,link1);
    bfs(t,DoubleFind::val,link2);
    DoubleFind::init();


//    puts("");
//    rep(i,1,n)rep(j,1,m){
//        printf("%d%c",dis1[i][j]," \n"[j==m]);
//    }
//    puts("");
//    rep(i,1,n)rep(j,1,m){
//        printf("%d%c",DoubleFind::val[i][j]," \n"[j==m]);
//    }
//    puts("");
//    rep(i,1,n+d)rep(j,1,m+d){
//        printf("%d%c",DoubleFind::Min[i][j]," \n"[j==m+d]);
//    }
//    puts("");
//    rep(i,1,n+d)rep(j,1,m+d){
//        printf("(%d,%d)%c",DoubleFind::Ans[i][j].fi,DoubleFind::Ans[i][j].se," \n"[j==m+d]);
//    }

    int ans=2e9;
    pill SS,TT;

    rep(i,1,n)rep(j,1,m){
        if(Map[i][j]!='X'){
            int V=dis1[i][j]+1+DoubleFind::Findval(i+d,j+d);
            if(V<ans){
                ans=V;
                SS={i,j};
                TT=DoubleFind::Ans[i+d][j+d];
            }
        }
    }

    int ans1=2e9;
    pill PP;
    rep(i,1,n)rep(j,1,m){
        if(Map[i][j]!='X'){
            int V=dis1[i][j]+DoubleFind::val[i][j];
            if(V<ans1){
                ans1=V;
                PP={i,j};
            }
        }
    }

    if(ans1>1e8&&ans>1e8){
        puts("-1");
        return 0;
    }
    printf("%d\n",min(ans,ans1));

    if(ans1<ans){
        SS=PP;
        TT=PP;
    }
    stack<pill>sta;
    bool same=(SS==TT);
    do{
        sta.push(SS);
        if(SS==s)break;
        SS=link1[SS.fi][SS.se];
    }while(1);
    while(!sta.empty()){
        printf("%d %d\n",sta.top().fi-1,sta.top().se-1);
        sta.pop();
    }
    if(!same){
        printf("%d %d\n",TT.fi-1,TT.se-1);
    }
    if(TT==t)return 0;
    TT=link2[TT.fi][TT.se];
    while(1){
        printf("%d %d\n",TT.fi-1,TT.se-1);
        if(TT==t)return 0;
        TT=link2[TT.fi][TT.se];
    }


    return 0;
}

发布了790 篇原创文章 · 获赞 348 · 访问量 22万+

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/105644958
今日推荐