题目分析
首先我们要明确,直接瞎广搜可以拿80分,所以怎么取舍是不是很明了?
如果你还是有一颗打正解的心…
好吧,祝你好运。
分析开始——
此题核心:状态为点,建图,进行最短路
状态为点
什么状态比较重要?目标棋子的位置,这是肯定的。再者是空格的位置。
不过事实上,重要的状态是空格和目标棋子相邻(第二步会说),也就是一个状态(x,y,tmp)是一个点,表示目标棋子在(x,y)位置,tmp代表空格的位置。我的代码中,tmp=0时表示在目标棋子上面,=1表示在下面,=2表示在左边,=3表示在右边。
建图
状态之间进行转移的代价为两点之间的边长。可以连边的节点有两种情况:
1.空格在不经过目标棋子的情况下移动到目标棋子身边另一位置。由于华容道的地图是不会改变的,所以这些边可以bfs暴力预先完成。
2.空格和目标棋子交换位置了,这两个状态之间的边长为1
进行最短路
首先bfs将空格移到目标棋子身边,然后就有四种可以作为起点的状态。因为我是使用spfa进行最短路的,所以只要合法(即空格可以移动到此位置),可以都加入处理队列。
然后spfa完毕后,有四种可能的终点(空格在目标棋子最终位置的不同方位),都查看一遍即可。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int n,m,q,tot;
int mp[33][33],dis[33][33],qx[1010],qy[1010];
int mvx[5]={-1,1,0,0},mvy[5]={0,0,-1,1};
int h[4010],to[40010],ne[40010],w[40010];
void add(int x,int y,int z)//建边
{to[++tot]=y,ne[tot]=h[x],h[x]=tot,w[tot]=z;}
void bfs(int sx,int sy,int bx,int by,int fx){//(sx,sy):空格位置,(bx,by):目标棋子位置
int i,ta=1,he=1,xx,yy,tx,ty;
memset(dis,0,sizeof(dis));
qx[1]=sx,qy[1]=sy,dis[sx][sy]=1;
while(he<=ta){
xx=qx[he],yy=qy[he];
for(i=0;i<=3;++i){
tx=xx+mvx[i],ty=yy+mvy[i];
if(mp[tx][ty]&&!dis[tx][ty]&&(tx!=bx||ty!=by))//注意这些限制条件
dis[tx][ty]=dis[xx][yy]+1,qx[++ta]=tx,qy[ta]=ty;
}
++he;
}
if(fx==4)return;
for(i=0;i<=3;++i){//情况1:空格在不经过目标棋子的情况下来到目标棋子身边其他方位
tx=bx+mvx[i],ty=by+mvy[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);//情况2:交换空格与目标棋子的位置
}
int d[4010],inq[4010];
void spfa(int bx,int by){
int i,x,tx,ty,tt;queue<int>q;
for(i=0;i<=4000;++i)d[i]=1e7,inq[i]=0;
for(i=0;i<=3;++i){//有4种可行的开始情况
tx=bx+mvx[i],ty=by+mvy[i],tt=bx*120+by*4+i;
if(dis[tx][ty])d[tt]=dis[tx][ty]-1,q.push(tt),inq[tt]=1;
}
while(!q.empty()){
x=q.front(),q.pop(),inq[x]=0;
for(i=h[x];i!=-1;i=ne[i])
if(d[x]+w[i]<d[to[i]]){
d[to[i]]=d[x]+w[i];
if(!inq[to[i]])inq[to[i]]=1,q.push(to[i]);
}
}
}
int main()
{
int i,j,sx,sy,mx,my,bx,by,ans;
scanf("%d%d%d",&n,&m,&q);memset(h,-1,sizeof(h));
for(i=1;i<=n;++i)
for(j=1;j<=m;++j)scanf("%d",&mp[i][j]);
for(i=1;i<=n;++i)
for(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--){
scanf("%d%d%d%d%d%d",&sx,&sy,&bx,&by,&mx,&my);
if(bx==mx&&by==my){puts("0");continue;}
bfs(sx,sy,bx,by,4);spfa(bx,by);ans=1e7;
for(i=0;i<=3;++i)ans=min(ans,d[mx*120+my*4+i]);//有4种可行的结束情况
if(ans<1e7)printf("%d\n",ans);
else puts("-1");
}
return 0;
}