题目链接:Click here~~
今天下午做了这道深搜题,弄了半天,终于对深搜有了初步的认识。
题目大意就是给你一个迷宫,要你判断有没有一条路径,可以在时间t时恰好到达终点。
搜索的魅力,无疑在于剪枝。对于这道题,可以有4种剪枝。
1.如果当前搜索的深度(时间)大于时间t,中止搜索。
2.如果已经搜索到结果,中止搜索。
3.如果当前所剩余的时间小于从当前位置到终点的理论最短时间,必定不能到达,中止搜索。
4.传说中的奇偶性剪枝,详细介绍如下:
我们把map看成这样:
/*
0 1 0 1 0 1
1 0 1 0 1 0
0 1 0 1 0 1
1 0 1 0 1 0
*/
它的规律是:0和1相间排列。仔细观察不难发现,当行号和列号同为奇数,或者同为偶数时,写0;否则,写1。
而且,从0的格子走1步,不管哪个方向,都会走到1的格子上。
于是我们得出这样的结论:
0->1 或 1->0 必定走奇数步,
0->0 或 1->1 必定走偶数步。
所以当我们遇到不满足上述两个结论的,可以推断它不能到达,所以中止搜索。
还有一种特殊情况,就是当地图上能走的点的个数(不包括起点)小于时间t的时候,显然不能到达,这时可以不用搜索,直接输出NO;
#include <stdio.h>
#include <string.h>
#include <stdlib.h> //gcc中abs()在stdlib.h里
int ko,fr_x,fr_y,to_x,to_y;
bool map[9][9];
int dir[]={0,1,0,-1,1,0,-1,0};
bool find;
void dfs(int x,int y,int step)
{
if(find == true || step >= ko) //剪枝1、2
return ;
/*
if(ko-step < abs(x-to_x) + abs(y-to_y)) //剪枝3
return ;
if( (ko-step)%2 != (abs(x-to_x) + abs(y-to_y))%2 )//剪枝4
return ;
*/
int cut = ko-step-abs(x-to_x)-abs(y-to_y);
if(cut<0 || cut&1) //剪枝3、4
return ;
for(int k=0;k<8;)
{
int _x = x + dir[k++];
int _y = y + dir[k++];
if(_x == to_x && _y == to_y && step+1 == ko)
{
find = true;
return ;
}
if(map[_x][_y] == 1)
{
map[_x][_y]=0;
dfs(_x,_y,step+1);
map[_x][_y]=1; //精华
}
}
}
int main()
{
int h,w;
while(scanf("%d%d%d",&h,&w,&ko),h)
{
memset(map,0,sizeof(map));
getchar();
int cnt=0;
for(int i=1;i<=h;i++)
{
for(int j=1;j<=w;j++)
{
char c = getchar();
switch(c)
{
case 'X':cnt++;break;
case 'S':fr_x=i,fr_y=j;break;
case 'D':to_x=i;to_y=j;break;
case '.':map[i][j]=1;break;
}
}
getchar();
}
if(h*w-cnt <= ko) //特殊情况
{
puts("NO");
continue;
}
find = false;
dfs(fr_x,fr_y,0);
if(find)
puts("YES");
else
puts("NO");
}
return 0;
}