思路挺难想的,一开始想着要以每个点预处理再SPFA,但是这样会很麻烦,而且会出问题
因为空格子在每个点的不同方向都是不一样的,所以我们考虑把状态抽象成点,用一个三维数组储存
id[i][j][k]表示空格在(i,j)的k方向
我们可以处理出状态之间的步数,可以用bfs做到
状态之间连好边,每次询问的时候设置一个起始状态和终止状态,将他们分别连向可转移的状态
具体看代码吧
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define maxn 35
#define M 810005
#define inf 0x3f3f3f3f
using namespace std;
int n,m,t,a[maxn][maxn],cnt,head[M],dis[maxn][maxn][5][5];
int id[maxn][maxn][5],tot,d[maxn][maxn],ans[M];
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
bool vis[M];
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') {if(c=='-') f=-1;c=getchar();}
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
struct EDGE{
int to,nxt,w;
}edge[M<<1];
inline void add(int x,int y,int z){
edge[++cnt].to=y; edge[cnt].nxt=head[x]; head[x]=cnt; edge[cnt].w=z;
}
inline bool judge(int x,int y){
return (x>0 && x<=n && y>0 && y<=m);
}
queue< pair<int,int> > q;
inline int bfs(int x1,int y1,int x2,int y2){
if(x1==x2 && y1==y2) return 0;//从x1,y1走到x2,y2的最少步数
while(!q.empty()) q.pop();
memset(d,0,sizeof d);
q.push(make_pair(x1,y1));
while(!q.empty()){
int x=q.front().first,y=q.front().second; q.pop();
for(int i=0;i<4;i++){
int nx=x+dx[i],ny=y+dy[i];
if(!judge(nx,ny) || !a[nx][ny] || d[nx][ny]) continue;
d[nx][ny]=d[x][y]+1;
if(nx==x2 && ny==y2) return d[nx][ny];
q.push(make_pair(nx,ny));
}
}
return inf;
}
inline void prework(){
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<4;k++)
id[i][j][k]=++tot;
memset(dis,0x3f,sizeof dis);
for(int i=1;i<=n;i++)//预处理(i,j),空格从其k方向移动到t方向需要的最少步数
for(int j=1;j<=m;j++)
if(a[i][j]){
a[i][j]=0;
for(int k=0;k<4;k++){
int x=i+dx[k],y=j+dy[k];
if(!judge(x,y) || !a[x][y]) continue;
for(int t=0;t<4;t++){
int nx=i+dx[t],ny=j+dy[t];
if(!judge(nx,ny) || !a[nx][ny]) continue;
dis[i][j][k][t]=bfs(x,y,nx,ny)+1;
}
}
a[i][j]=1;
}//(i,j)往k方向移动一个格子的步数,状态取反
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<4;k++)
for(int t=0;t<4;t++)
if(dis[i][j][k][t]<inf)
add(id[i][j][k],id[i+dx[t]][j+dy[t]][t^1],dis[i][j][k][t]);
return;
}
queue<int> Q;
inline int SPFA(int s,int t){
memset(ans,0x3f,sizeof ans); memset(vis,0,sizeof vis);
while(!Q.empty()) Q.pop();
Q.push(s); vis[s]=1; ans[s]=0;
while(!Q.empty()){
int u=Q.front(); Q.pop();
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(ans[v]>ans[u]+edge[i].w){
ans[v]=ans[u]+edge[i].w;
if(!vis[v]) vis[v]=1,Q.push(v);
}
} vis[u]=0;
}
return ans[t]<inf?ans[t]:-1;
}
int main(){
n=rd(); m=rd(); t=rd();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[i][j]=rd();
prework();
while(t--){
int ex=rd(),ey=rd(),sx=rd(),sy=rd(),tx=rd(),ty=rd();
if(!a[sx][sy] || !a[tx][ty] || !a[ex][ey]) {puts("-1");continue;}
if(sx==tx && sy==ty) {puts("0");continue;}
int S=++tot,T=++tot;
a[sx][sy]=0;
for(int i=0;i<4;i++){
int x=sx+dx[i],y=sy+dy[i];
if(a[x][y] && judge(x,y)){
int tmp=bfs(ex,ey,x,y);//空格子走到起点周围
if(tmp<inf) add(S,id[sx][sy][i],tmp);
}
}
a[sx][sy]=1;
for(int i=0;i<4;i++){
int x=tx+dx[i],y=ty+dy[i];
if(a[x][y] && judge(x,y))
add(id[tx][ty][i],T,0);
}
printf("%d\n",SPFA(S,T));
}
return 0;
}