这一题的dfs算是简单,但是本题难就难在剪枝。不剪枝的dfs也能过但是也稍微做一点优化,才能AC。但是如果使用 奇偶剪枝 的话效果就比优化明显多了
虽然几次优化可以达到405MS(感觉应该是极致了,划线的为奇偶剪枝),但是不如奇偶剪枝一剪就到202MS。
现在我来介绍下奇偶剪枝:
首先举个例子,有如下4*4的迷宫,'.'为可走路段,'X'为障碍不可通过
S...
....
....
...D
从S到D的最短距离为两点横坐标差的绝对值+两点纵坐标差的绝对值 = abs(Sx - Dx) + abs(Sy - Dy) = 6,这个应该是显而易见的。
遇到有障碍的时候呢
S.XX
X.XX
...X
...D
你会发现不管你怎么绕路,最后从S到达D的距离都是最短距离+一个偶数,这个是可以证明的
而我们知道:
奇数 + 偶数 = 奇数
偶数 + 偶数 = 偶数
因此不管有多少障碍,不管绕多少路,只要能到达目的地,走过的距离必然是跟最短距离的奇偶性是一致的。
所以,这样对于一部分不可行的方案几乎就是瞬间搞定
下面直接上代码了:
#include <iostream>
#include <stdlib.h>
#include <cstring>
using namespace std;
char maze[10][10];
bool dfs(int x, int y, int T){
// 剩一步时即可判断是否为出口,找到返回true
if (T == 1){
if (maze[x-1][y] == 'D') return true;
if (maze[x+1][y] == 'D') return true;
if (maze[x][y-1] == 'D') return true;
if (maze[x][y+1] == 'D') return true;
return false;
}
else{
// 标记走过
maze[x][y] = 'X';
// 深度优先搜索
if (maze[x-1][y] == '.' && dfs(x-1, y, T-1)) return true;
if (maze[x+1][y] == '.' && dfs(x+1, y, T-1)) return true;
if (maze[x][y-1] == '.' && dfs(x, y-1, T-1)) return true;
if (maze[x][y+1] == '.' && dfs(x, y+1, T-1)) return true;
// 还原走过
maze[x][y] = '.';
return false;
}
}
int main(){
int sx,sy,gx,gy;
int N,M,T;
while(cin>>N>>M>>T,T){
memset(maze,'X',sizeof(maze));
for(int i=0;i<N;i++){
for(int j=0;j<M;j++){
cin>>maze[i][j];
if(maze[i][j]=='S')
sx=i,sy=j;
else if(maze[i][j]=='D')
gx=i,gy=j;
}
}
if( ( abs(sx-gx)+abs(sy-gy) - T ) & 1 )
//奇偶剪枝
cout<<"NO"<<endl;
else{
if(dfs(sx,sy,T))
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
return 0;
}