正在入门搜索,从dfs开始,听说这道题很好,做了(WA了好多次)之后感觉的确很好。这道题包含多种剪枝及回溯。
思路:对于每个可行点,从上下左右四个方向去dfs,同时剪去不必要的答案;
剪枝:奇偶剪枝,时间剪枝;
代码含详细注解;
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<iostream>
using namespace std;
int sx,sy,ex,ey;//标记起始和终点位置;
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};//方向数组:上下左右;
char map[25][25];//构建地图;
bool vis[25][25];//记录是否走过;
int n,m,t;//地图的行列和所需总时间;
bool flag;//标记是否能走到;
void dfs(int x,int y,int time)
{
int i;
if(x<0||x>=n||y<0||y>=m)
{
return ;//出界
}
if(map[x][y]=='D'&&time==t)
{
flag=true;
return ;//到达终点且符合条件
}
if(t-time<abs(x-ex)+abs(y-ey))
{
return ;//剩下的时间小于最短路走过去所需时间,剪枝;
}
if((t-time)%2!=(abs(x-ex)+abs(y-ey))%2)
{
return ;//奇偶剪枝:到达终点所需时间的奇偶性和到达终点的路程奇偶性不同;
}
if(flag)
{
return ;//如果已经成功,不用再搜了;
}
vis[x][y]=true;
for(i=0;i<4;i++)
{
int nx,ny;
nx=x+dir[i][0];
ny=y+dir[i][1];
if(!vis[nx][ny])//如果该处没走过的话:墙vis永远都是true,所以永远不能走;
{
dfs(nx,ny,time+1);
vis[nx][ny]=false;//回溯;
}
}
}
int main()
{
int i,j;
while(scanf("%d%d%d",&n,&m,&t)!=EOF)
{
if(n==0&&m==0&&t==0)
{
break;
}
memset(vis,false,sizeof(vis));
flag=false;
for(i=0;i<n;i++)
{
scanf("%s",map+i);//%s不用getchar()吃回车,%c要!
}
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
if(map[i][j]=='S')
{
sx=i;
sy=j;
}
if(map[i][j]=='D')
{
ex=i;
ey=j;
}
if(map[i][j]=='X')
{
vis[i][j]=true;//因为墙不能走,故vis标记为已走,这样dfs时永远不会进去;
}
}
}
dfs(sx,sy,0);
if(flag)
{
printf("YES\n");
}
else
{
printf("NO\n");
}
}
return 0;
}