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; }