这道题用到的方法是: DFS+奇偶剪枝+回溯
一般的DFS是不需要回溯的,仅仅做一个标记而已,但是这道题一个递归经历的,下次可以重用,所以需要回溯。
DFS深度优先遍历:就是循环+递归,循环是为了保证都能够有机会进行递归。递归就是深度有限的体现。
回溯:回溯是指当前递归搜索路径不满足条件时,但是还有其他未搜索路径,存在满足条件的可能性,需要返回起点重新搜索(回溯)。由于可能和当前路径某些点重复,所以回溯需要记得搜索后把状态回复到初始值。
剪枝:剪枝技术说白了,就是提前去除某些绝对不可能的情况,避免浪费时间,做明知道不可能的事,减少搜索条件,缩小搜索范围。这里奇偶剪枝意思就是把剩余步数和剩余距离的差的绝对值为奇数的条件剪掉。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
bool mark[7][7];
int dpx,dpy;
int spx,spy;
int n=0,m=0,t=0;
int dix[]={-1,1,0,0};
int diy[]={0,0,-1,1};
int ABS(int x){
return x<0?-x:x;
}
bool dfs(int i,int j,int step){
//stop condition step==t but not D
if(step==t){
if(mark[dpx][dpy])
return true;
else
return false;
}
int tmp=ABS(i-dpx)+ABS(j-dpy)-ABS(step-t);
//cut condition
if(tmp>0||tmp%2!=0){
return false;
}
// dfs
for(int s=0;s<4;s++){
int ni=i+dix[s];
int nj=j+diy[s];
if(ni<0||ni>=n||nj>=m||nj<0||mark[ni][nj]) continue;
mark[ni][nj]=true;
if(dfs(ni,nj,step+1)){
return true;
}
mark[ni][nj]=false;
}
return false;
}
int main()
{
//index of door and the start point
string s;
while(scanf("%d%d%d",&n,&m,&t)&&n){
memset(mark,false,sizeof(mark));
//input
for(int i=0;i<n;i++){
cin>>s;
for(int j=0;j<m;j++){
//record index of S and D;
if(s[j]=='S'){
spx=i;
spy=j;
mark[i][j]=true;
}else if(s[j]=='D'){
dpx=i;
dpy=j;
}else if(s[j]=='X'){
mark[i][j]=true;
}
// TODO set mark[i][j]=true if s[i][j]=='X'
}
}
if(dfs(spx,spy,0)){
printf("YES\n");
}else{
printf("NO\n");
}
}
return 0;
}