题目

小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时间。

小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:

在一个 n \times mn×m 棋盘上有 n \times mn×m个格子,其中有且只有一个格子是空白的,其余 n \times m-1n×m−1个格子上每个格子上有一个棋子,每个棋子的大小都是 1 \times 11×1 的;

有些棋子是固定的,有些棋子则是可以移动的;

任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。

游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。

给定一个棋盘,游戏可以玩 qq 次,当然,每次棋盘上固定的格子是不会变的, 但是棋盘上空白的格子的初始位置、 指定的可移动的棋子的初始位置和目标位置却可能不同。第 ii 次玩的时候, 空白的格子在第 EX_iEX
i

行第 EY_iEY
i

列,指定的可移动棋子的初始位置为第 SX_iSX
i

行第 SY_iSY
i

列,目标位置为第 TX_iTX
i

行第 TY_iTY
i

列。

假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。

思路

考虑暴力做法,则是对于每个询问bfs,这样很明显会超时

优化:
考虑有用的状态
只有当空白块到了指定块的四周,它才可以带着指定块移动
从这一个状态可以转移到四种状态,分别是空白块到了指定块的其他三个方向以及空白块与指定块交换位置
这样就是一个最短路问题,可以用spfa解决了
至于空白块到其他三个方向的距离,可以向bfs预处理出来,直接与处理出每个块每个方向上有空白块的情况然后连边
对于每次询问进行spfa
还有就是开始时空白块不一定在指定块周围
这时候就要bfs处理出空白块到指定块周围所需的步数
最后统计时取空白块在目标块的四个方向时距离最短的就是了

代码

#include<bits/stdc++.h>
using namespace std;
const int N=4077;
int n,m,q,tot;
int mp[33][33],dis[33][33],qx[1010],qy[1010];
int dx[5]={-1,1,0,0},dy[5]={0,0,-1,1};
int ls[N],to[N*10],nxt[N*10],id[N*10];
int d[N],v[N];
void add(int x,int y,int z)
{
	to[++tot]=y;id[tot]=z;nxt[tot]=ls[x];ls[x]=tot;
}
void bfs(int sx,int sy,int bx,int by,int fx){
	int h=1,t=1;
	memset(dis,0,sizeof(dis));
	qx[h]=sx;qy[h]=sy;dis[sx][sy]=1;
	while(h<=t){
		int x=qx[h],y=qy[h];
		for(int i=0;i<4;i++){
			int tx=x+dx[i],ty=y+dy[i];
			if(mp[tx][ty]&&!dis[tx][ty]&&(tx!=bx||ty!=by)){
				dis[tx][ty]=dis[x][y]+1;qx[++t]=tx;qy[t]=ty;
			}
		}
		h++;
	}
	if(fx==4) return;
	for(int i=0;i<4;i++){
		int tx=bx+dx[i],ty=by+dy[i];
		if((tx!=sx||ty!=sy)&&dis[tx][ty]){
			add(bx*120+by*4+fx,bx*120+by*4+i,dis[tx][ty]-1);
		}  
	}
	add(bx*120+by*4+fx,sx*120+sy*4+fx^1,1);
}
void spfa(int sx,int sy){
	queue<int> q;
	for(int i=0;i<=4005;i++) d[i]=1e7,v[i]=0;
	for(int i=0;i<=3;i++){
		int tx=sx+dx[i],ty=sy+dy[i];
		if(dis[tx][ty]) d[sx*120+sy*4+i]=dis[tx][ty]-1,q.push(sx*120+sy*4+i),v[sx*120+sy*4+i]=1;
	}
	while(q.size()){
		int x=q.front();q.pop();
		v[x]=0;
		for(int i=ls[x];i;i=nxt[i]){
			int y=to[i],z=id[i];
			if(d[y]>d[x]+z){
				d[y]=d[x]+z;
				if(!v[y]) v[y]=1,q.push(y);
			}
		}
	}
}
int main(){
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			scanf("%d",&mp[i][j]);
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(!mp[i][j]) continue;
			if(mp[i-1][j]) bfs(i-1,j,i,j,0);
			if(mp[i+1][j]) bfs(i+1,j,i,j,1);
			if(mp[i][j-1]) bfs(i,j-1,i,j,2);
			if(mp[i][j+1]) bfs(i,j+1,i,j,3);
		}
	}
	while(q--){
		int mx,my,sx,sy,bx,by;
		scanf("%d%d%d%d%d%d",&mx,&my,&sx,&sy,&bx,&by);
		if(sx==bx&&sy==by){printf("0\n");continue;}
		bfs(mx,my,sx,sy,4);spfa(sx,sy);int ans=1e7;
		for(int i=0;i<=3;i++){
			ans=min(ans,d[bx*120+by*4+i]);
		}
		if(ans<1e7) printf("%d\n",ans);
		else printf("-1\n");
	}
}