一看到这道题,
首先可以用脚指头想到,
既然目标是让指定棋子移到目标位置上,
那么决定棋盘状态的就只有指定棋子的位置和空格的位置两个因素。
接着,可以用手指头想到,
既然,指定格子只有在周围有空格时才能动,
那么实际上状态就只有棋子的位置,以及空格在棋子的哪个方向。
共
4nm
4
n
m
个,对每个状态建点。
接着我们会发现,对于一个棋盘状态,有两种转移:
1.让棋子移到空格,代价为1
2.让空格到处跑,跑到棋子的另一个方向去,代价可以用bfs暴力算出
两种转移分别建边,SPFA即可。
注意:SPFA一开始,要算出空格从初始位置移到棋子四周的代价,作为初始代价。
个人认为是一道很好很难的最短路题。
具体实现见代码如下:
#include <iostream>
#include <cstring>
#define INF 0x3f3f3f3f
using namespace std;
int d[4][2]= {{1,0},{-1,0},{0,1},{0,-1}},sx,sy,tx,ty,ex,ey,cost[35][31][4][4],dis[35][35][4],n,m,l,a[35][35];
bool vis[35][35],b[35][35][4];
struct data {
int x,y,k;
} q[1000000];
int bfs(int _ex,int _ey,int _sx,int _sy,int k) {
memset(vis,0,sizeof(vis));
int head=1,tail=0;
vis[_sx][_sy]=1;
vis[_ex][_ey]=1;
q[++tail]=(data) {
_ex,_ey,0
};
while(tail>=head) {
int x=q[head].x,y=q[head].y,s=q[head].k;
if((_sx+d[k][0]==x)&&(_sy+d[k][1]==y)) {
return s;
}
for(int i=0; i<4; i++) {
if(a[x+d[i][0]][y+d[i][1]]&&(!vis[x+d[i][0]][y+d[i][1]])) {
q[++tail]=(data) {
x+d[i][0],y+d[i][1],s+1
};
vis[x+d[i][0]][y+d[i][1]]=1;
}
}
head++;
}
return INF;
}
void pre() {
memset(cost,0x3f,sizeof(cost));
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++) {
if(a[i][j]) {
for(int di=0; di^4; di++) {
if(a[i+d[di][0]][j+d[di][1]]) {
cost[i][j][di][di]=0;
for(int dj=0; dj^di; dj++) {
if(a[i+d[dj][0]][j+d[dj][1]]) {
cost[i][j][di][dj]=cost[i][j][dj][di]=bfs(i+d[di][0],j+d[di][1],i,j,dj);
}
}
}
}
}
}
}
}
int spfa() {
memset(dis,0x3f,sizeof(dis));
for(int i=0; i<4; i++) {
dis[sx][sy][i]=bfs(ex,ey,sx,sy,i);
}
memset(b,0,sizeof(b));
int head=1,tail=0;
for(int i=0; i<4; i++) {
q[++tail]=(data) {
sx,sy,i
};
b[sx][sy][i]=1;
}
while(tail>=head) {
int x=q[head].x,y=q[head].y,k=q[head].k;
b[x][y][k]=0;
head++;
int vx=x+d[k][0],vy=y+d[k][1];
for(int i=0; i<4; i++) {
if(a[vx][vy]) {
if(dis[x][y][k]+cost[vx][vy][k^1][i]+1<dis[vx][vy][i]) {
dis[vx][vy][i]=dis[x][y][k]+cost[vx][vy][k^1][i]+1;
if(!b[vx][vy][i]) {
q[++tail]=(data) {
vx,vy,i
};
b[vx][vy][i]=1;
}
}
}
}
}
int ret=INF;
for(int i=0; i^4; i++) {
ret=min(ret,dis[tx][ty][i]);
}
return ret;
}
int main(int argc, char** argv) {
cin>>n>>m>>l;
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++) {
cin>>a[i][j];
}
}
pre();
for(int i=1; i<=l; i++) {
cin>>ex>>ey>>sx>>sy>>tx>>ty;
if(sx==tx&&sy==ty) {
cout<<0<<endl;
continue;
}
int ret=spfa();
cout<<(ret<INF?ret:-1)<<endl;
}
return 0;
}