YESNONONONOYES
题意:中文题不解释,注意一点就是所有的都是针对当前状态;
思路:这是一道需要记录转弯路径的题目;两枚棋子之间必须是0,而且两枚棋子必须相等,否则不成立;
我们在结构体中记录找到这枚棋子时的上一个方向,如果不同,则转弯次数加1;如果超过三次就直接跳过就好;(我这里第
一次的方向为-1,转弯次数为0;不管下一个往哪里走都会加1,所以我的为不超过三次);
****比较难理解的是我开了一个数组记录了找到该点的最小转弯次数,这是为什么呢?
*** 这是因为,以前我们用bfs一般都是找最小,最短路径等问题,找到之后直接 break跳出,而我们此题也没有标记,没有
break,我们从一点到另一点的转折次数最小是无法确定的;所以我们需要开一个数组,存到该点的最小转弯次数;
举个例子,比如我们现在走到(3,3)这个点转弯了两次,方向朝上;但是我们现在走到(3,3)转了三次弯,方向也是朝上,那么
转了三次的这个就应该放弃,因为同样的方向,同样的点,转了两次弯的一定能到达转了三次弯所到达的那些;同样的,如果
我们现在走到(3,3)转弯一次,方向朝上,那么就应该去更新它的最小转弯次数为1;但是q.step<=num[q.a][q.b]的等号不能
忘,如果转弯次数相同,但是方向不同,虽然方向不同但是可能另一个方向的就是答案;
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
int a[1100][1100];
int num[1100][1100];
int go[4][2]= {{0,1}, {0, -1}, {1, 0}, {-1, 0}};
int n,m,t;
int x1,x2,y1,y2;
struct node
{ int a,b;
int dir;//当前转向;
int step;//转弯次数;
};
int check(int x,int y)
{ if(x<1||x>n||y<1||y>m)
return 0;
return 1;
}
int bfs()
{ if(a[x1][y1]!=a[x2][y2]||!a[x1][y1])return 0;
int i,j;
for(i=1;i<=n;++i)
for(j=1;j<=m;++j)
num[i][j]=1000;
queue<node>Q;
node q,p;
q.a=x1;
q.b=y1;
q.step=0;
q.dir=-1;
Q.push(q);
num[x1][y1]=0;
while(!Q.empty())
{ p=Q.front();
Q.pop();
for(i=0;i<4;i++)
{ q=p;
q.a+=go[i][0];
q.b+=go[i][1];
if(check(q.a,q.b)==0)
continue;
if(q.dir!=i)
q.step++;//方向不同,转弯次数++;
q.dir=i;
if(q.step>3)//如果转弯次数大于3直接剪掉;
continue;
if(q.a==x2&&q.b==y2)
return 1;
if(a[q.a][q.b])
continue;
if(q.step<=num[q.a][q.b])//记录最小的转弯次数入队;
{ num[q.a][q.b]=q.step;
Q.push(q);
}
}
}
return 0;
}
int main()
{ int i,j;
while(scanf("%d%d",&n,&m)!=EOF)
{ if(n==0&&m==0)
break;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&a[i][j]);
scanf("%d",&t);
for(i=0;i<t;i++)
{ scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
if(bfs())
puts("YES");
else
puts("NO");
}
}
return 0;
}