题意:在一个坐标内,给定起点和终点,问能否恰好在t时刻到达终点。
以前很少写搜索题,所以看到这个题,就按照普通的深搜写了一下,交上去超时了。后来在网上搜了一下才知道,要剪枝才行。可是,我以前从没写过剪枝,不知道怎么剪,就按照别人的思路往下想。看懂以后,我对剪枝的理解是:对于一些没有必要继续搜索的路径,不再往下深搜,提前返回到上一层。花了半天时间调试代码,终于AC了。
奇偶剪枝:根据题目,doggie必须在第t秒到达门口。也就是需要走t-1步。设doggie开始的位置为(sx,sy),目标位置为(ex,ey).如果abs(ex-x)+abs(ey-y)为偶数,则abs(ex-x)和abs(ey-y)奇偶性相同,所以需要走偶数步;
当abs(ex-x)+abs(ey-y)为奇数时,则abs(ex-x)和abs(ey-y)奇偶性不同,到达目标位置就需要走奇数步。先判断奇偶性再搜索可以节省很多时间,不然的话容易超时。t-sum为到达目标位置还需要多少步。因为题目要求doggie必须在第t秒到达门的位置,所以(t-step)和abs(ex-x)+abs(ey-y)的奇偶性必然相同。因此temp=(t-step)-abs(ex-x)+abs(ey-y)必然为偶数。
#include<stdio.h>
#include<string.h>
int flag,sx,sy,ex,ey,num;
int n,m,t,vis[10][10];
int dx[]={-1,0,1,0};
int dy[]={0,-1,0,1};
char map[10][10];
int abs(int p){
return p>=0?p:-p;
}
void dfs(int x,int y,int sum)
{
int i,xx,yy;
if(flag==1) return ;
if(x==ex&&y==ey&&sum==t)
{
flag=1;
return ;
}
int mindis=abs(x-ex)+abs(y-ey);
if(mindis>t-sum||(mindis+t-sum)%2!=0)
return;
for(i=0;i<4;i++)
{
xx=x+dx[i];
yy=y+dy[i];
if(xx>=0&&xx<n&&yy>=0&&yy<m&&!vis[xx][yy]&&map[xx][yy]!='X')
{
vis[xx][yy]=1;
dfs(xx,yy,sum+1);
vis[xx][yy]=0;
}
}
}
int main()
{
int i,j;
while(~scanf("%d%d%d",&n,&m,&t)){
if(n==0&&m==0&&t==0)
break;
num=0;
for(i=0;i<n;i++){
scanf("%s",map[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')
num++;
}
}
if(n*m - num -1< t)
{
printf("NO\n");
continue;
}
flag=0;
memset(vis,0,sizeof(vis));
vis[sx][sy] = 1;
dfs(sx, sy, 0);
if(flag)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}