【NOIP2013】 华容道 bfs预处理+bfs
这一题我们考虑一个最裸的算法:
我们设$dp[i][j][k][l]$表示当前棋子在$(i,j)$且空格在$(k,l)$时的最小步数
然后显然随便转移一下就好了,时间复杂度为$O(q(nm)^2)$。可以获得$80$分的好成绩(我自测的时候只打了这个)
我们发现这一题有一些很优秀的性质:
首先整个图是静态的,且起点,终点,出现空格的位置均非障碍物。
那么对于这个性质,我们做一些微小的预处理。
考虑到当空格与目标棋子四相邻的时候,棋子才能往空格内移动。那么整个走棋的过程可以理解为:调整空格位置-移动棋子到空格里-调整空格位置
我们设$f[i][j][k][l]$表示在不经过$(i,j)$的情况下,将空格从$(i+wx[k],j+wy[k])$移动到$(i+wx[l],j+wy[l])$的最小步数,其中$wx,wy$满足$|wx[i]+wy[i]|=1$,显然有四种组合。
对于每一个$f[i][j][k][l]$,我们通过一次$bfs$去求解。
预处理$f$的时间复杂度显然为$O(16nm)$。
下面考虑每一组询问:
若起点和终点的坐标相同,那么显然输出$0$就好了。
若起点和终点坐标不相同,我们先考虑将空格移动到起点四相邻的位置,所需要的最小步数显然可以通过一次$bfs$求得。
然后我们设$d[i][j][k]$表示当前棋子在$(i,j)$时,空格在$(i+wx[k],j+wy[k])$的最小步数。
显然随便$bfs$就可以进行更新了。最后的答案显然是$min(d[tx][ty][])$。
时间复杂度$O(16nm+4qnm)$。跑得飞快。
1 #include<bits/stdc++.h> 2 #define M 32 3 #define INF 16843009 4 using namespace std; 5 int n,m,q,mp[M][M]={0},dis[M][M]={0},d[M][M][4]={0},f[M][M][4][4]={0}; 6 const int wx[]={0,1,0,-1}; 7 const int wy[]={1,0,-1,0}; 8 queue<int> qx,qy,qk; 9 void bfs(int X,int Y){ 10 memset(dis,1,sizeof(dis)); 11 qx.push(X); qy.push(Y); dis[X][Y]=0; 12 while(!qx.empty()){ 13 X=qx.front(); qx.pop(); 14 Y=qy.front(); qy.pop(); 15 for(int i=0;i<4;i++){ 16 int _x=X+wx[i],_y=Y+wy[i]; 17 if(mp[_x][_y]&&dis[_x][_y]>dis[X][Y]+1){ 18 dis[_x][_y]=dis[X][Y]+1; 19 qx.push(_x); qy.push(_y); 20 } 21 } 22 } 23 } 24 void move(int x,int y){ 25 memset(dis,1,sizeof(dis)); 26 qx.push(x); qy.push(y); dis[x][y]=0; 27 while(!qx.empty()){ 28 x=qx.front(); qx.pop(); 29 y=qy.front(); qy.pop(); 30 for(int i=0;i<4;i++){ 31 int _x=x+wx[i],_y=y+wy[i]; 32 if(mp[_x][_y]&&dis[_x][_y]>dis[x][y]+1){ 33 dis[_x][_y]=dis[x][y]+1; 34 qx.push(_x); qy.push(_y); 35 } 36 } 37 } 38 } 39 40 41 void bfs(){ 42 while(!qx.empty()){ 43 int x=qx.front(); qx.pop(); 44 int y=qy.front(); qy.pop(); 45 int k=qk.front(); qk.pop(); 46 for(int i=0;i<4;i++){ 47 int _x=x+wx[i],_y=y+wy[i]; 48 if(mp[_x][_y]==0) continue; 49 if(d[_x][_y][(i+2)&3]>d[x][y][k]+f[x][y][k][i]+1){ 50 d[_x][_y][(i+2)&3]=d[x][y][k]+f[x][y][k][i]+1; 51 qx.push(_x); qy.push(_y); qk.push((i+2)&3); 52 } 53 } 54 } 55 } 56 57 int main(){ 58 scanf("%d%d%d",&n,&m,&q); 59 for(int i=1;i<=n;i++) 60 for(int j=1;j<=m;j++) scanf("%d",&mp[i][j]); 61 62 for(int i=1;i<=n;i++) 63 for(int j=1;j<=m;j++) 64 if(mp[i][j]){ 65 mp[i][j]=0; 66 for(int k=0;k<4;k++) 67 if(mp[i+wx[k]][j+wy[k]]){ 68 bfs(i+wx[k],j+wy[k]); 69 for(int l=0;l<4;l++) 70 f[i][j][k][l]=dis[i+wx[l]][j+wy[l]]; 71 } 72 mp[i][j]=1; 73 } 74 75 while(q--){ 76 int ex,ey,sx,sy,tx,ty; 77 cin>>ex>>ey>>sx>>sy>>tx>>ty; 78 if(sx==tx&&sy==ty){ 79 printf("0\n"); 80 continue; 81 } 82 mp[sx][sy]=0; 83 move(ex,ey); 84 mp[sx][sy]=1; 85 memset(d,1,sizeof(d)); 86 for(int i=0;i<4;i++) 87 if(mp[sx+wx[i]][sy+wy[i]]){ 88 qx.push(sx); 89 qy.push(sy); 90 qk.push(i); 91 d[sx][sy][i]=dis[sx+wx[i]][sy+wy[i]]; 92 } 93 bfs(); 94 int minn=INF; 95 for(int i=0;i<4;i++) 96 minn=min(minn,d[tx][ty][i]); 97 if(minn==INF) printf("-1\n"); 98 else cout<<minn<<endl; 99 } 100 }