HDU 1010 Tempter of the Bone(DFS回溯+剪枝)
http://acm.hdu.edu.cn/showproblem.php?pid=1010
题意:
给你一个N*M的迷宫和一个时间T,迷宫中为X的格子是不能走的,现在给你起点和终点.问你能不能在正好T秒的时候从起点到达终点,且不能走回头路.
分析:
注意本题用回溯法做,回溯法与普通DFS的区别在于:回溯法需要还原之前的场景。
假设我们DFS处理的时候不剪枝,那么就是这样:
尝试往前走一步
标记当前格为X
if ( DFS(step+1)) return true;
解除当前格标记
那么这题的剪枝是什么?
其中第一个剪枝很容易想到,由于我们每秒只能向任意方向走1步.所以如果终点距离当前位置的坐标差>我们当前剩余时间,我们明显是不可能按时到达的.
第二个剪枝是:剩余时间t-(终点与当前位置的绝对距离和) == 偶数.因为如果是奇数的话,你是无论如何也不可能准时到达终点的.(这个可以自己想象验证一下.)
代码实现的时候出现了一个BUG,找了很久.这里要注意的是起点’S’我们之后是不能走的,’S’点在初始我们已经走过了.
AC代码:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=10;
int dr[]={-1,1,0,0};//上下左右
int dc[]={0,0,-1,1};
char map[maxn][maxn];
int R,C,T;
int sr,sc,er,ec;
bool dfs(int r,int c,int t)//t表示当前剩余时间
{
if(t==0)
{
if(r==er&&c==ec) return true;
return false;
}
if( t<(abs(er-r)+abs(ec-c)) || (t-abs(er-r)-abs(ec-c) )%2==1) return false; //代价剪枝
for(int d=0;d<4;d++)
{
int nr=r+dr[d], nc=c+dc[d];
if(nr<0||nr>=R||nc<0||nc>=C||map[nr][nc]=='X') continue;
map[nr][nc]='X';
if(dfs(nr,nc,t-1)) return true;
map[nr][nc]='.';//回溯
}
return false;
}
int main()
{
while(scanf("%d%d%d",&R,&C,&T)==3 && R)
{
for(int i=0;i<R;i++)
for(int j=0;j<C;j++)
{
scanf(" %c",&map[i][j]);
if(map[i][j]=='S')
{
sr=i, sc=j;
map[i][j]='.';
}
if(map[i][j]=='D')
{
er=i, ec=j;
map[i][j]='.';
}
}
map[sr][sc]='X'; //错误1,少了这句就是WA
if(dfs(sr,sc,T)) printf("YES\n");
else printf("NO\n");
}
return 0;
}