问题描述:http://acm.hdu.edu.cn/showproblem.php?pid=1175
思路很清晰,但是因为实现的方式和代码的问题,纠结了好久,最后请牛人(YWJ)帮忙,终于好了。
采用广度搜索,队列实现,先入先出,实现的时候,关键是对走过的路径的标识,防止陷入死循环。用数组has[][]标记一个点最小的拐角数。还有设立方向数组op[][],只要一个for就解决了四个方向,防止代码的重复。当然要注意判断下一步压入队列的和当前位置的关系,到底有没有拐角等。还有当拐角大于2时直接无视掉。
程序代码:
#include<iostream>
#include<queue>
using namespace std;
int res[1010][1010];//保存数组
int has[1010][1010];//标记到该节点最少的拐角(重点。。。)
int op[4][2]={-1,0,1,0,0,1,0,-1};
struct node
{
int x;
int y;
int step;//标记拐角数
int id;//标记方向,-1直走,0,1,2,3分别是向上,下,右,左
};
queue<node> myQue;
bool run(int x1,int y1,int x2,int y2,int n,int m)
{
int i,j;
int x,y;
node temp,now;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
has[i][j]=5;
while(!myQue.empty())
myQue.pop();
temp.x=x1;
temp.y=y1;
temp.step=-1;
temp.id=-1;
myQue.push(temp);
has[x1][y1]=-1;
while(!myQue.empty())
{
temp=myQue.front();
myQue.pop();
//如果前一步不是直走到,那么按其直走的方向走一步。因为额for循环中没有走。
for(i=0;i<4;i++)
{
//如果拐弯数大于等于二的时候不能拐弯
if(temp.step>=2&&temp.id!=i) continue;
x=temp.x+op[i][0];
y=temp.y+op[i][1];
if(x==x2&&y==y2) return true;
if(x<1||x>n||y<1||y>m) continue;
if(res[x][y]!=0) continue;
now.x=x;
now.y=y;
if(i==temp.id)
{
now.step=temp.step;
now.id=temp.id;
}else{
now.id=i;
now.step=temp.step+1;
}
//若经过该点的拐角数比保存的要小,则入队列
if(has[now.x][now.y]>=now.step)
{
has[now.x][now.y]=now.step;
myQue.push(now);
}
}
}
return false;
}
int main(int argc, char* argv[])
{
int n,m;
int i,j;
int t,a,b,c,d;
while(cin>>n>>m)
{
if(n==0&&m==0)
break;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
cin>>res[i][j];
cin>>t;
while(t--)
{
cin>>a>>b>>c>>d;
if(res[a][b]==0||res[c][d]==0||(a==c&&b==d))
{
cout<<"NO"<<endl;
continue;
}
if(res[a][b]!=res[c][d])
cout<<"NO"<<endl;
else if(run(a,b,c,d,n,m))
cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
return 0;
}