题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1175
|
题目分析:这题是经典的dfs+剪枝;
1.dfs(x,y,dic,k);前两个参数是坐标x和y。第三个参数是移动的方向(起始参数为-1),第四个参数为转弯的次数
2.剪枝技巧一,如果转弯次数大于2或者已经找到目标;
3.剪枝技巧二,如果转弯次数等于2,但是这时候的位置和目标位置不在一条线上;
代码:
#include<iostream>
#include<string.h>
using namespace std;
int n,m,a[1005][1005],book[1005][1005];
int x1,y1,x2,y2;
int l;//0代表前一步横着走的,1代表前一步竖着走的
int flag;
void dfs(int x,int y,int dic,int k)//dic用来记录方向,k用来记录线的转折次数
{
if(k>2||flag==1)//如果转弯的次数大于2或者已经找到就终止
return ;//这个剪枝必须有,不然肯定超时
if(k==2&&(x-x2)!=0&&(y-y2)!=0)//判断两次转弯后是否与目标在一条直线上
return ;//这个剪枝没有的话虽然不超时,但是时间大大增加,有的话250MS左右,没有的话9500MS左右
if(x==x2&&y==y2&&k<=2)//终点
{
flag=1;
return ;
}
int tx,ty;
int next[4][2]={0,1,1,0,0,-1,-1,0};//右下左上
for(int i=0;i<4;i++)
{
tx=x+next[i][0];
ty=y+next[i][1];
if(tx<1||tx>n||ty<1||ty>m||book[tx][ty]==1)
continue;
if(a[tx][ty]==0||(tx==x2&&ty==y2))
{
book[tx][ty]=1;
if(dic==-1||dic==i)//如果是起始方向或者同向
dfs(tx,ty,i,k);
else
dfs(tx,ty,i,k+1);
book[tx][ty]=0;
}
}
return ;
}
int main()
{
int i,j,q;
while(cin>>n>>m)
{
if(n==0&&m==0)
break;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
cin>>a[i][j];
cin>>q;
while(q--)
{
memset(book,0,sizeof(book));//这个初始化要注意,想想为什么
flag=0;//初始化
cin>>x1>>y1>>x2>>y2;
if(a[x1][y1]!=a[x2][y2]||a[x1][y1]==0)
{
cout<<"NO"<<endl;
continue;
}
dfs(x1,y1,-1,0);//起始方向为-1
if(flag==1)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
return 0;
}
通过这题学习的技巧:
1.像深搜的题目,如果只是为了找到搜到目标,可以用一个flag标记,找到目标是把flag变为1,这样可以剪枝的时候用。
注意事项:通过这样剪枝,标记数组就不会还原,如果多组输入的,记得每次初始化。
2.像这题,是从起始点找到终点的题,可以在判断边界时,一块判断标记数组。在判断该坐标是否符合条件时,可以加一个是否为终点的坐标的条件(因为一般终点坐标和能走通的路数组值不一样)。
既然看到底了,如果感觉有一点点帮助,何不留个赞再走呢!!!