以转弯次数step作为代价,假设出发就转弯了一次,那么step<=3如果能够到达目标,代表可行。
扩展节点的时候,如果step==1,由于还有两次转弯的机会,所以所有的节点都扩展。
当step==2的时候,只有一次转弯的机会了,那么就要取x或者y坐标和终点的x,y坐标相等的,加入队列。
当step==3时,只用判断是否到达节点就行了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
#define inf 0x3f3f3f3f
#define N 1005
#define M 1005
int dir[4][2]={1,0,-1,0,0,1,0,-1};
int dp[4][N][M];
int map[N][M];
int n,m,q,sx,sy,dx,dy;
struct node
{
int x,y,dir;
int step;
}f,temp;
bool bfs()
{
int i;
f.x=sx;
f.y=sy;
f.step=0;
queue<node>q;
for(i=0;i<4;i++)
{
f.dir=i;
q.push(f);
dp[i][sx][sy]=0;
}
while(!q.empty())
{
f=q.front();q.pop();
if(f.x==dx&&f.y==dy)return true;
if(f.step==3)continue;
for(i=0;i<4;i++)
{
temp=f;
if(i==temp.dir)continue;
temp.dir=i;
temp.step++;
while(1)
{
temp.x+=dir[i][0];
temp.y+=dir[i][1];
if(temp.x>=1&&temp.x<=n&&temp.y>=1&&temp.y<=m&&(map[temp.x][temp.y]==0||(temp.x==dx&&temp.y==dy)))
{
if(dp[temp.dir][temp.x][temp.y]>temp.step&&temp.step==1)
{
dp[temp.dir][temp.x][temp.y]=temp.step;
q.push(temp);
}
else if(dp[temp.dir][temp.x][temp.y]>temp.step&&temp.step==2)
{
if(temp.x==dx||temp.y==dy)
{
dp[temp.dir][temp.x][temp.y]=temp.step;
q.push(temp);
}
}
else if(temp.step==3)
{
if(temp.x==dx&&temp.y==dy)return true;
}
}
else break;
}
}
}
return false;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n+m==0)break;
int i,j;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)scanf("%d",&map[i][j]);
}
scanf("%d",&q);
while(q--)
{
memset(dp,inf,sizeof dp);
scanf("%d%d%d%d",&sx,&sy,&dx,&dy);
if(map[sx][sy]==map[dx][dy]&&map[sx][sy]!=0)
{
if(bfs())printf("YES\n");
else printf("NO\n");
}
else printf("NO\n");
}
}
return 0;
}