这道题有多次询问,如果每次询问bfs做的话,会TLE。发现询问是在一张图上,所以可以对一些信息预处理。处理dis[x][y][k][h] ,代表x,y这个点的k方向上有空格,它想要走到h方向的最小步数。这东西可以n^2×4×4次bfs预处理。然后状态是dis[x][y][k]。状态之间转移一下,就变成了Spfa。
每次从起点跑到终点,统计下答案。注意数据中有起点终点相同的情况。
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
int n,m,qq;
bool mp[35][35];
int ex,ey;
struct Point{
int x,y,b;
}tt[10005];
queue<Point> Q;
int cx[]={0,1,0,-1,0};
int cy[]={0,0,1,0,-1};
bool vis[32][32];
bool check(int x,int y)
{return x>0&&x<=n&&y>0&&y<=m&&mp[x][y];}
void init()
{
while(!Q.empty()) Q.pop();
memset(vis,0,sizeof(vis));
}
int bfs(int x,int y,int k,int h)
{
Point S;init();S.b=0;
S.x=x+cx[k];S.y=y+cy[k];
int Ex=x+cx[h],Ey=y+cy[h];
Q.push(S);
while(!Q.empty())
{
Point B=Q.front();Q.pop();
int nx=B.x,ny=B.y;
if(nx==Ex&&ny==Ey) return B.b;
for(int i=1;i<=4;i++)
{
int x=nx+cx[i],y=ny+cy[i];
if(check(x,y)&&!vis[x][y])
{
Point C=B;C.b++;
C.x=x;
C.y=y;
vis[C.x][C.y]=1;
Q.push(C);
}
}
}
return -1;
}
queue<int> q;
int dis[35][35][5][5];
int id[35][35][5];
int inf=1e9+7,T=0;
int cst[10005];
int f(int i)
{
if(i==1) return 3;
if(i==2) return 4;
if(i==3) return 1;
return 2;
}
void bfs2(int x,int y,int ex,int ey)
{
init();vis[x][y]=1;vis[ex][ey]=1;
Point S;S.x=x;S.y=y;S.b=0;
Q.push(S);
while(!Q.empty())
{
Point A=Q.front();Q.pop();
int nx=A.x,ny=A.y;
for(int i=1;i<=4;i++)
{
if(ex+cx[i]==nx&&ey+cy[i]==ny)
{
int v=id[ex][ey][i];
q.push(v);cst[v]=A.b;
break;
}
}
for(int i=1;i<=4;i++)
{
x=nx+cx[i];y=ny+cy[i];
if(check(x,y)&&!vis[x][y])
{
Point B;vis[x][y]=1;
B=(Point){x,y,A.b+1};
Q.push(B);
}
}
}
}
bool inq[10005];
int spfa(int Ex,int Ey)
{
int ans=inf;
while(!q.empty())
{
int v=q.front();q.pop();inq[v]=0;
int x=tt[v].x,y=tt[v].y,k=tt[v].b;
for(int i=1;i<=4;i++)
{
int X=x+cx[i],Y=y+cy[i];
if(check(X,Y))
{
int Id=id[X][Y][f(i)];
int vv=id[x][y][k];
if(cst[Id]>cst[vv]+dis[x][y][k][i])
{
cst[Id]=cst[vv]+dis[x][y][k][i];
if(X==Ex&&Y==Ey) ans=min(ans,cst[Id]);
if(!inq[Id])
{
q.push(Id);
inq[Id]=1;
}
}
}
}
}
if(ans==inf) ans=-1;
return ans;
}
int main()
{
freopen("puzzle20.in","r",stdin);
freopen("puzzle.ans","w",stdout);
scanf("%d%d%d",&n,&m,&qq);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&mp[i][j]);
for(int h=1;h<=4;h++)
for(int k=1;k<=4;k++)
dis[i][j][h][k]=inf;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=4;k++)
if(mp[i][j]&&check(i+cx[k],j+cy[k]))
{
id[i][j][k]=++T;
tt[T].x=i;
tt[T].y=j;
tt[T].b=k;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(mp[i][j])
{
mp[i][j]=0;
for(int k=1;k<=4;k++)
{
if(mp[i+cx[k]][j+cy[k]])
{
for(int h=1;h<=4;h++)
{
if(mp[i+cx[h]][j+cy[h]])
{
int w=bfs(i,j,k,h);
if(w==-1) continue;
dis[i][j][k][h]=w+1;
}
}
}
}
mp[i][j]=1;
}
}
while(qq--)
{
int x1,x2,y1,y2;
scanf("%d%d",&x1,&y1);//
scanf("%d%d",&x2,&y2);// start
scanf("%d%d",&ex,&ey);// end
for(int i=1;i<=T;i++)
cst[i]=inf;
bfs2(x1,y1,x2,y2);
if(x2==ex&&y2==ey) puts("0");
else cout<<spfa(ex,ey)<<endl;
}
}