http://acm.hdu.edu.cn/showproblem.php?pid=1010
题目大意:这道题就是讲有一只狗要吃骨头,结果进入了一个迷宫陷阱,迷宫里每走过一个地板费时一秒,该地板就会在下一秒塌陷,所以你不能在该地板上逗留。迷宫里面有一个门,只能在特定的某一秒才能打开,让狗逃出去。现在题目告诉你迷宫的大小和门打开的时间,问你狗可不可以逃出去,可以就输出YES,否则NO。
解题思路:这道题,要用到剪枝搜索来做,否则会超时。剪掉的条件是,如果可走地板数目小于给定的时间,绝对不可能得救。还有就是狗走到门的时间必须和题目给定的时间是同奇同偶的,否则也不能在指定的那秒到达门,也不可能得救,剪掉这两种情况后。就用深度搜索来做。从起点出发,深搜周围的路,走过的路就标记为不可走,一直搜索下去,如果搜索失败就回溯,恢复原数据,把可能的路都搜索一遍过去,看看是否有可行方案。
关于剪枝,没有剪枝的搜索不太可能,一个是奇偶剪枝,一个是路径剪枝
奇偶剪枝:
把矩阵标记成如下形式:
0,1,0,1,0
1,0,1,0,1
0,1,0,1,0
1,0,1,0,1
很明显,如果起点在0 而终点在1 那显然 要经过奇数步才能从起点走到终点,依次类推,奇偶相同的偶数步,奇偶不同的奇数步
在读入数据的时候就可以判断,并且做剪枝,当然做的时候并不要求把整个矩阵0,1刷一遍,读入的时候起点记为(Si,Sj) 终点记为(Di,Dj) 判断(Si+Sj) 和 (Di+Dj) 的奇偶性就可以了
路径剪枝:
矩阵的大小是N*M 墙的数量记为num 如果能走的路的数量 N*M - num 小于时间T,就是说走完也不能到总的时间的,这显然是错误的,可以直接跳出了
剪枝3:就是记录当前点到终点的最短路,如果小于剩余的时间的话,就跳出
代码:
#include<stdio.h>
#include<math.h>
#include<string.h>
#define N 10
int dir[4][2]={-1,0,1,0,0,-1,0,1};
int flag,di,dj,T,m,n;
char str[N][N];
void dfs(int si,int sj,int t)
{
int i,temp;
if(si==di&&sj==dj&&t==T)
{
flag=1;
return ;
}
if(si<0||si>=m||sj<0||sj>=n)
return ;
temp=T-t-abs(si-di)-abs(sj-dj);
if(temp<0||temp%2!=0) //奇偶剪枝,剪枝3
return ;
for(i=0;i<4;i++)
{
//千万要注意的是节点越界的情况, dfs(int si,int sj,int t)的时候一定要把 si, sj 控制在给你的矩阵内
if(si+dir[i][0]>=0&&si+dir[i][0]<m&&sj+dir[i][1]>=0&&sj+dir[i][1]<n)
if(str[si+dir[i][0]][sj+dir[i][1]]!='X')
{
str[si+dir[i][0]][sj+dir[i][1]]='X';
dfs(si+dir[i][0],sj+dir[i][1],t+1);
if(flag) return ;
str[si+dir[i][0]][sj+dir[i][1]]='.'; //搜索失败,恢复原数据
}
}
return ;
}
int main()
{
int i,j,si,sj,t,num;
while(scanf("%d%d%d",&m,&n,&T)!=EOF)
{
getchar();
if(m==0&&n==0&&T==0)
break;
num=0;
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
scanf("%c",&str[i][j]);
if(str[i][j]=='S')
{
si=i;sj=j;
}
else if(str[i][j]=='D')
{
di=i;dj=j;
}
else if(str[i][j]=='X')
num++;
}
getchar();
}
if(m*n-num<=T) //路径剪枝
{
printf("NO\n");
continue;
}
flag=0;
str[si][sj]='X';
dfs(si,sj,0);
if(flag)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}