借大神的一句话:在考场上遇到这种题就只有呵呵了。
当时以为是一道搜索题,然后用了BFS,双向BFS,A*,发现还是BFS最快- -。(可能我的A*写丑了…)然而只骗了45分。据说有大神的BFS搜索得了80分……
正解:预处理+最短路。
先预处理出可能的目标格子(即所以可移动的格子)到达四周格子(假定是空格)的最短路。
处理每一次询问时,预处理出空格到目标格子四周格子(当然不能经过目标格子)的最少步数。之后将状态(i,j,k)(表示目标格子到达点(i,j)并且空格在该点的k方向)当做一个点,用 tmp[i][j][k] 表示到达该状态需要的最少步数。做一次最短路。
扩展状态:
1.空格与格子交换。
2.空格换到格子的其他方向。
果真是一道神题,在此膜拜在赛场上AC的大牛们。%%%
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#define MAXN 35
using namespace std;
const int inf=0x3f3f3f3f;
int dis[MAXN][MAXN] ,step[MAXN][MAXN][4][4] ,tmp[MAXN][MAXN][4] ;
bool in[MAXN][MAXN][4] ;
int map[MAXN][MAXN] ,n ,m ,x0 ,y0 ,xb ,yb ,xe ,ye ;
int d1[4]={0,1,0,-1};
int d2[4]={1,0,-1,0};
struct node
{
int x ,y ,k ;
};
queue<node>myque ;
struct aaa
{
int x ,y ;
};
queue<aaa>q;
void init(int a,int b)//预处理目标棋子在位置(a,b)时,到达相邻格子所需的步数(当然不能经过(a,b))
{
int dx ,dy ;
for(int i=0;i<4;++i)
{
dx=a+d1[i] ,dy=b+d2[i] ;
if(dx<1||dy<1||dx>n||dy>m)continue;
if(map[dx][dy])
myque.push((node){dx,dy,i});
}
int x ,y ,k ,temp ,temp2 ;
while(!myque.empty())
{
memset(dis,inf,sizeof dis);
x=myque.front().x ,y=myque.front().y ,k=myque.front().k ;
myque.pop();
dis[x][y]=0 ;
q.push((aaa){x,y});
while(!q.empty())
{
temp=q.front().x ,temp2=q.front().y ;
q.pop();
for(int i=0;i<4;++i)
{
dx=temp+d1[i] ,dy=temp2+d2[i] ;
if(dx<1||dy<1||dx>n||dy>m)continue;
if(map[dx][dy]&&(dx!=a||dy!=b)&&dis[dx][dy]==inf)
{
dis[dx][dy]=dis[temp][temp2]+1;
q.push((aaa){dx,dy});
}
}
}
for(int i=0;i<4;++i)
{
dx=a+d1[i] ,dy=b+d2[i] ;
if(dx<1||dy<1||dx>n||dy>m)continue;
if(map[dx][dy]&&(dx!=x||dy!=y)&&dis[dx][dy]!=inf)
step[a][b][k][i]=dis[dx][dy];
}
}
}
void pre()//预处理当前空格(x0,y0)到目标格子相邻格子的最短路
{
memset(dis,inf,sizeof dis);
dis[x0][y0]=0;
q.push((aaa){x0,y0});
int x ,y ,dx ,dy ;
while(!q.empty())
{
x=q.front().x ,y=q.front().y ;
q.pop();
for(int i=0;i<4;++i)
{
dx=x+d1[i] ,dy=y+d2[i] ;
if(dx<1||dy<1||dx>n||dy>m)continue;
if(map[dx][dy]&&(dx!=xb||dy!=yb)&&dis[dx][dy]==inf)
{
dis[dx][dy]=dis[x][y]+1 ;
q.push((aaa){dx,dy});
}
}
}
}
queue<node>point;
int solve()
{
if(xb==xe&&yb==ye)return 0;
pre();
memset(tmp,inf,sizeof tmp);
int dx ,dy ;
// tmp[x][y][k]保存点(x,y)到k方向的相邻点的最短路
for(int i=0;i<4;++i)
{
dx=xb+d1[i] ,dy=yb+d2[i] ;
if(dx<1||dy<1||dx>n||dy>m)continue;
if(map[dx][dy]&&dis[dx][dy]!=inf)
{
tmp[xb][yb][i]=dis[dx][dy];
point.push((node){xb,yb,i});
in[xb][yb][i]=1;
}
}
int x ,y ,k ;
while(!point.empty())
{
x=point.front().x ,y=point.front().y ,k=point.front().k ;
point.pop();
in[x][y][k]=0;
dx=x+d1[k] ,dy=y+d2[k] ;
//将点(x,y)移到空格处
if(tmp[dx][dy][(k+2)%4]>tmp[x][y][k]+1)
{
tmp[dx][dy][(k+2)%4]=tmp[x][y][k]+1;
if(!in[dx][dy][(k+2)%4])
{
in[dx][dy][(k+2)%4]=1;
point.push((node){dx,dy,(k+2)%4});
}
}
//空格(也与点(x,y)相邻)移动到点(x,y)相邻的格子去
for(int i=0;i<4;i++)
{
dx=x+d1[i] ,dy=y+d2[i] ;
if(dx>0&&dy>0&&dx<=n&&dy<=m&&map[dx][dy]&&i!=k&&step[x][y][k][i]!=inf)
{
if(tmp[x][y][i]>tmp[x][y][k]+step[x][y][k][i])
{
tmp[x][y][i]=tmp[x][y][k]+step[x][y][k][i];
if(!in[x][y][i])
{
in[x][y][i]=1;
point.push((node){x,y,i});
}
}
}
}
}
int ans=inf;
for(int i=0;i<4;++i)
ans=min(ans,tmp[xe][ye][i]);
if(ans==inf)return -1;
return ans;
}
int main()
{
int T ;
scanf("%d%d%d",&n,&m,&T);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%d",&map[i][j]);
memset(step,inf,sizeof(step));
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(map[i][j])
init(i,j);
while(T--)
{
scanf("%d%d%d%d%d%d",&x0,&y0,&xb,&yb,&xe,&ye);
printf("%d\n",solve());
}
return 0;
}