[Luogu1979][NOIP2013]华容道(BFS+SPFA)
考虑从起点到终点的过程,一定是先将空格子移到指定格子旁边,和指定格子交换,再移到下一个指定格子要到的地方,再交换,如此反复。
于是问题分为两个部分:
1.给定两个曼哈顿距离为2的格子求最短路,BFS即可。
2.根据1的结果决定从起点到终点的路径,使用SPFA求解。
其中,第一个问题空格子显然不能经过指定格子,BFS过程中需要特判。第二个问题的状态为(x,y,k),表示当前指定格子在(x,y),空格子在它的哪个方向(1<=k<=4)。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 5 using namespace std; 6 7 const int N=35,inf=1e9; 8 const int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1}; 9 bool inq[1<<14],mp[N][N]; 10 int n,m,Q,ex,ey,sx,sy,tx,ty,d[1<<14],dis[N][N],cost[1<<14]; 11 struct P{ int x,y; }q[1<<14]; 12 struct S{ int x,y,dir; }q2[1<<14]; 13 14 int F(int x,int y,int a,int b){ return x<<9 | y<<4 | a<<2 | b; } 15 int F(int x,int y,int k){ return x<<7 | y<<2 | k; } 16 17 void bfs(int x0,int y0,int x1,int y1){ 18 memset(dis,-1,sizeof(dis)); 19 mp[x1][y1]=0; int st=0,ed=1,tot=4; q[1]=(P){x0,y0}; dis[x0][y0]=0; 20 while (st<ed){ 21 int x=q[++st].x,y=q[st].y; 22 if (abs(x-x1)+abs(y-y1)==1) 23 if (--tot==0) break; 24 rep(k,0,3){ 25 int x2=x+dx[k],y2=y+dy[k]; 26 if (mp[x2][y2] && dis[x2][y2]==-1) 27 dis[x2][y2]=dis[x][y]+1,q[++ed]=(P){x2,y2}; 28 } 29 } 30 mp[x1][y1]=1; 31 } 32 33 void init(){ 34 rep(i,1,n) rep(j,1,m) if (mp[i][j]) 35 rep(p,0,3){ 36 int x1=i+dx[p],y1=j+dy[p]; 37 if (!mp[x1][y1]) continue; 38 bfs(i,j,x1,y1); 39 rep(q,0,3){ 40 int x2=x1+dx[q],y2=y1+dy[q]; 41 if (~dis[x2][y2]) cost[F(x1,y1,p^1,q)]=dis[x2][y2]+1; 42 } 43 } 44 } 45 46 int spfa(){ 47 int st=0,ed=0; 48 memset(d,0x3f,sizeof(d)); 49 bfs(ex,ey,sx,sy); 50 rep(k,0,3){ 51 int x1=sx+dx[k],y1=sy+dy[k]; 52 if (dis[x1][y1]==-1) continue; 53 q2[++ed]=(S){sx,sy,k}; d[F(sx,sy,k)]=dis[x1][y1]; inq[F(sx,sy,k)]=1; 54 } 55 while (st<ed){ 56 int x=q2[++st].x,y=q2[st].y,dir=q2[st].dir,u=F(x,y,dir); inq[u]=0; 57 rep(k,0,3){ 58 int x1=x+dx[k],y1=y+dy[k],c=cost[F(x,y,dir,k)],v=F(x1,y1,k^1); 59 if (mp[x1][y1] && c && d[v]>d[u]+c){ 60 d[v]=d[u]+c; if (!inq[v]) q2[++ed]=(S){x1,y1,k^1},inq[v]=1; 61 } 62 } 63 } 64 int ans=inf; 65 rep(k,0,3) ans=min(ans,d[F(tx,ty,k)]); 66 return ans==inf ? -1 : ans; 67 } 68 69 int main(){ 70 freopen("a.in","r",stdin); 71 freopen("a.out","w",stdout); 72 scanf("%d%d%d",&n,&m,&Q); 73 rep(i,1,n) rep(j,1,m) scanf("%d",&mp[i][j]); 74 init(); 75 while (Q--){ 76 scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty); 77 if (sx==tx && sy==ty) { puts("0"); continue; } 78 printf("%d\n",spfa()); 79 } 80 return 0; 81 }