ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

给出一张四连通的网格图,'#'代表墙,'.'代表空地,'S'代表出发点,'C'代表目的地,地图四周都是墙,求S到C的最短路。
走的时候可以向上下左右中的某个方向发射奇怪的东西(portals),portals会贴在发射方向的墙上。
地图上只允许同时存在两个portals,如果已经发射了两个再发射第三个,那么你需要在之前的那两个中的选一个使它消失。
两个portals可以存在于一块墙的两面,但不能存在于一块墙的同面。
当你身边是墙且那块墙上有面向你的portals时,你可以走进那个portals,从另一个portals出来。
相邻两点距离为1,走portals距离也为1

Input

第一行2个数R,C,表示矩形的长和宽
接下来R行,每行一个长为C的字符串,表示这张图

Output

输出一行表示答案

显然同个位置的传送门不会被用两次。由于传送门要走到才能传送且放置不花时间,可以认为入口传送门在进入的一瞬间才放置。当前在某个方格时,出口传送门有4个位置可以放置,而入口传送门则贪心地走到最近的墙边放置。预处理每个方格4个方向放置传送门的位置和到墙的最近距离,然后就可以用dijkstra算法求最短路,由于最短路长度不超过nm,可以用桶代替堆优化最短路,总复杂度O(nm),达到理论最优。

#include<cstdio>
int n,m,sx,sy,tx,ty;
int q[1100007][2],ql=0,qr=0;
char s[1007][1007];
int l1[1007][1007],l2[1007][1007];
int xd[]={-1,0,1,0},yd[]={0,-1,0,1};
int us[1007][1007];
int ds[1007][1007];
int ls[1007][1007];
int rs[1007][1007];
int es[5100007],enx[5100007],e0[1000007],ep=2,now=0;
void push(int x,int y,int z){
    if(l2[x][y]<=z)return;
    l2[x][y]=z;
    es[ep]=x<<10|y;enx[ep]=e0[z];e0[z]=ep++;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%s",s[i]+1);
        for(int j=1;j<=m;++j){
            if(s[i][j]=='S')sx=i,sy=j,s[i][j]='.';
            if(s[i][j]=='C')tx=i,ty=j,s[i][j]='.';
        }
    }
    for(int i=0;i<=n+1;++i){
        for(int j=0;j<=m+1;++j)if(s[i][j]!='.'){
            q[qr][0]=i;q[qr++][1]=j;
        }else l1[i][j]=l2[i][j]=n*m;
    }
    while(ql!=qr){
        int x=q[ql][0],y=q[ql++][1];
        for(int d=0;d<4;++d){
            int x1=x+xd[d],y1=y+yd[d];
            if(x1<1||x1>n||y1<1||y1>m)continue;
            if(s[x1][y1]=='.'&&l1[x1][y1]>l1[x][y]+1){
                l1[x1][y1]=l1[x][y]+1;
                q[qr][0]=x1;q[qr++][1]=y1;
            }
        }
    }
    for(int i=0;i<=n+1;++i){
        for(int j=0;j<=m+1;++j)if(s[i][j]!='.'){
            if(s[i-1][j]=='.')for(int k=i-1;s[k][j]=='.';--k)ds[k][j]=i-1;
            if(s[i+1][j]=='.')for(int k=i+1;s[k][j]=='.';++k)us[k][j]=i+1;
            if(s[i][j-1]=='.')for(int k=j-1;s[i][k]=='.';--k)rs[i][k]=j-1;
            if(s[i][j+1]=='.')for(int k=j+1;s[i][k]=='.';++k)ls[i][k]=j+1;
        }
    }
    push(sx,sy,0);
    while(1){
        for(;!e0[now];++now);
        for(int i=e0[now];i;i=enx[i]){
            int x=es[i]>>10,y=es[i]&1023;
            if(l2[x][y]!=now)continue;
            if(x==tx&&y==ty)return printf("%d",l2[x][y]),0;
            for(int d=0;d<4;++d){
                int x1=x+xd[d],y1=y+yd[d];
                if(x1<1||x1>n||y1<1||y1>m)continue;
                if(s[x1][y1]=='.')push(x1,y1,l2[x][y]+1);
            }
            if(us[x][y])push(us[x][y],y,l2[x][y]+l1[x][y]);
            if(ds[x][y])push(ds[x][y],y,l2[x][y]+l1[x][y]);
            if(ls[x][y])push(x,ls[x][y],l2[x][y]+l1[x][y]);
            if(rs[x][y])push(x,rs[x][y],l2[x][y]+l1[x][y]);
        }
        ++now;
    }
    return 0;
}

 

posted on 2016-12-12 14:14  nul  阅读(311)  评论(0编辑  收藏  举报