感觉和以前做过的一个推箱子很像,都是可以用bfs解决的,而且都是手玩出结论。
因为起始棋子肯定是要和空格交换的,所以第一件事是先把空格移到棋子旁边。然后讨论怎么设计搜索状态。由于和推箱子实在太像了,所以直接借鉴,发现空格总是要贴着棋子走的要不然就是换个贴的方向继续走(这里的走就是指交换)。于是绑定两者,设计状态$f_{i,j,dir}$表示在棋子在某个格子,空格在上下左右四方位时候的最小移动次数。显然可以暴力bfs跑,但是这样没有经过优化,效率不高,实际上只要把它改的像最短路算法一点就行了,比如套个dijkstra,把每种状态和他可以推到的下一步状态(分为交换,或者空格跑到另一侧,这个的步数可以提前预处理)之间连边,边权即步数,这样建个图之后就是最短路了,起点有4个,终点有4个,$O(Qn^2\text{log}n^2)$,避免了bfs庞大的搜索树。
然后注意一个很容易忽略的细节。。我第一发就是这么挂掉的。。起点和终点在同一个位置要特判,不然会加上空格到起点的距离然后跪好多点。
code可能是我有史以来写过的最丑的,一堆循环展开。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 #define dbg(x) cerr << #x << " = " << x <<endl 8 using namespace std; 9 typedef long long ll; 10 typedef double db; 11 typedef pair<int,int> pii; 12 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 13 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 14 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;} 15 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;} 16 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;} 17 template<typename T>inline T read(T&x){ 18 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1; 19 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x; 20 } 21 const int N=30+2,INF=0x3f3f3f3f; 22 int mp[N][N],f[N][N][4][4],id[N][N][4],cnt; 23 int n,m,Q,hx,hy,sx,sy,tx,ty; 24 int qx[114514],qy[114514],dis[N][N],l,r; 25 inline void bfs_step(int x,int y){ 26 memset(dis,0x3f,sizeof dis);qx[l=r=1]=x,qy[1]=y,dis[x][y]=0; 27 while(l<=r){ 28 int i=qx[l],j=qy[l++]; 29 if(!mp[i-1][j]&&MIN(dis[i-1][j],dis[i][j]+1))qx[++r]=i-1,qy[r]=j; 30 if(!mp[i+1][j]&&MIN(dis[i+1][j],dis[i][j]+1))qx[++r]=i+1,qy[r]=j; 31 if(!mp[i][j-1]&&MIN(dis[i][j-1],dis[i][j]+1))qx[++r]=i,qy[r]=j-1; 32 if(!mp[i][j+1]&&MIN(dis[i][j+1],dis[i][j]+1))qx[++r]=i,qy[r]=j+1; 33 } 34 } 35 struct thxorz{int to,nxt,w;}G[100000]; 36 int Head[5000],tot; 37 inline void Addedge(int x,int y,int z){ 38 G[++tot].to=y,G[tot].nxt=Head[x],Head[x]=tot,G[tot].w=z; 39 G[++tot].to=x,G[tot].nxt=Head[y],Head[y]=tot,G[tot].w=z; 40 } 41 int dist[5000]; 42 priority_queue<pii,vector<pii>,greater<pii> > q; 43 #define y G[j].to 44 inline void dij(int xx,int yy){ 45 memset(dist,0x3f,sizeof dist); 46 if(id[xx][yy][0])q.push(make_pair(dist[id[xx][yy][0]]=dis[xx-1][yy],id[xx][yy][0])); 47 if(id[xx][yy][1])q.push(make_pair(dist[id[xx][yy][1]]=dis[xx][yy+1],id[xx][yy][1])); 48 if(id[xx][yy][2])q.push(make_pair(dist[id[xx][yy][2]]=dis[xx+1][yy],id[xx][yy][2])); 49 if(id[xx][yy][3])q.push(make_pair(dist[id[xx][yy][3]]=dis[xx][yy-1],id[xx][yy][3])); 50 while(!q.empty()){ 51 int x=q.top().second,d=q.top().first;q.pop(); 52 if(dist[x]^d)continue; 53 for(register int j=Head[x];j;j=G[j].nxt)if(MIN(dist[y],d+G[j].w))q.push(make_pair(dist[y],y)); 54 } 55 } 56 #undef y 57 int main(){//freopen("test.in","r",stdin);freopen("test.ans","w",stdout); 58 read(n),read(m),read(Q);memset(mp,0x3f,sizeof mp); 59 for(register int i=1;i<=n;++i)for(register int j=1;j<=m;++j)read(mp[i][j]),mp[i][j]^=1; 60 for(register int i=1;i<=n;++i)for(register int j=1;j<=m;++j)if(!mp[i][j]){ 61 mp[i][j]=1; 62 if(!mp[i-1][j])bfs_step(i-1,j),f[i][j][0][1]=dis[i][j+1],f[i][j][0][2]=dis[i+1][j],f[i][j][0][3]=dis[i][j-1],id[i][j][0]=++cnt; 63 if(!mp[i][j+1])bfs_step(i,j+1),f[i][j][1][0]=dis[i-1][j],f[i][j][1][2]=dis[i+1][j],f[i][j][1][3]=dis[i][j-1],id[i][j][1]=++cnt; 64 if(!mp[i+1][j])bfs_step(i+1,j),f[i][j][2][0]=dis[i-1][j],f[i][j][2][1]=dis[i][j+1],f[i][j][2][3]=dis[i][j-1],id[i][j][2]=++cnt; 65 if(!mp[i][j-1])bfs_step(i,j-1),f[i][j][3][0]=dis[i-1][j],f[i][j][3][1]=dis[i][j+1],f[i][j][3][2]=dis[i+1][j],id[i][j][3]=++cnt; 66 mp[i][j]=0; 67 } 68 for(register int i=1;i<=n;++i)for(register int j=1;j<=m;++j)if(!mp[i][j]){ 69 for(register int thx=0;thx<4;++thx)for(register int orz=0;orz<4;++orz) 70 if(orz^thx&&id[i][j][thx]&&id[i][j][orz])Addedge(id[i][j][thx],id[i][j][orz],f[i][j][thx][orz]); 71 if(id[i][j][0])Addedge(id[i][j][0],id[i-1][j][2],1); 72 if(id[i][j][3])Addedge(id[i][j][3],id[i][j-1][1],1); 73 } 74 while(Q--){ 75 read(hx),read(hy),read(sx),read(sy),read(tx),read(ty); 76 if(sx==tx&&sy==ty){puts("0");continue;} 77 mp[sx][sy]=1;bfs_step(hx,hy);mp[sx][sy]=0; 78 dij(sx,sy); 79 int tmp=_min(dist[id[tx][ty][0]],_min(dist[id[tx][ty][1]],_min(dist[id[tx][ty][2]],dist[id[tx][ty][3]]))); 80 printf("%d\n",tmp<INF?tmp:-1); 81 } 82 return 0; 83 }
总结:棋盘类问题求最小解有常用方法就是最短路建模,注意考虑状态设计有效性,必要时跑分层图。