[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
",spfa());
79     }
80     return 0;
81 }
原文地址:https://www.cnblogs.com/HocRiser/p/9837534.html