暑假的时候,小明和朋友去迷宫中寻宝。然而,当他拿到宝贝时,迷宫开始剧烈震动,他感到地面正在下沉,他们意识到这是一个陷阱!他们想尽一切办法逃出去。
迷宫是一个大小为 N*M 的长方形,迷宫中有一扇门。一开始,门是关着的,他会在第 t 秒的时间打开。因为,小明和朋友必须在第 t 秒到大门口。每一秒,他都可以向上下左右四个方向移动一个点。一旦他移动了,他刚才所在的点就消失,(这意味着他不能回到他已经走过的点)。他不能在一个点上停留超过一秒,并且不能走障碍点。小明和朋友能安全的逃出吗?
输入由多个测试用例组成。每个测试用例的第一行包含三个整数 N、M 和 T ( 1 < N , M < 7 ; 0 < T < 50 ),分别表示迷宫的大小和门打开的时间。接下来的N行给出迷宫布局,每一行包含M个字符。下列字母分别表示:
“X”: 一堵墙,小明和朋友不能在上面停留
“S”: 起点
“D”: 门
“.”: 可以走的点
输入以 3 个 0 时结束。这个测试用例不需要处理。
对于每组样例输出一行。
如果小明能够安全逃出,输出 “YES” ,否则输出 “NO”。
Sample Input
4 4 5
S.X.
…X.
…XD
…
3 4 5
S.X.
…X.
…D
0 0 0
Sample Output
NO
YES
首先就是最经典的奇偶性剪枝, 观察样例我们可以发现, 对于两点之间曼哈顿距离为奇数的, 则只能在奇数时间内到达. 为偶数的, 之内在偶数时间内到达. 这样的话我们判断到不匹配的直接就剪掉了.
还有一个小剪枝, 就是如果我们发现可走的格子数量比时间还要多, 自然也要剪掉了.
剩下的就是直接搜了, 注意要求恰好 t==T
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef long long LL;
const int inf = 1<<30;
const int maxn = 10;
int N, M, T;
int sx, sy, ex, ey;
bool mp[maxn][maxn], vis[maxn][maxn];
int act[4][2] = {{0,1},{1,0},{-1,0},{0,-1}};
bool Dfs(int x, int y, int t){
if(t > T) return false; //剪枝
if(x==ex && y==ey && t==T) return true; //终点
int cx, cy;
for(int i = 0; i < 4; i++){
cx = x+act[i][0], cy = y+act[i][1];
if(cx>0&&cx<=N&&cy>0&&cy<=M && !mp[cx][cy] && !vis[cx][cy]){
vis[cx][cy] = true;
if(Dfs(cx, cy, t+1)) return true;
vis[cx][cy] = false;
}
}
return false;
}
int main()
{
char c;
while(cin>>N>>M>>T, N||M||T){
ms(mp, 0); ms(vis, 0);
int block = 0;
for(int i = 1; i <= N; i++)
for(int j = 1; j <= M; j++){
cin >> c;
if(c=='S') sx = i, sy = j;
else if(c=='D') ex = i, ey = j;
else if(c=='X') mp[i][j] = 1, ++block;
}
//
if(T>(N*M-block) || (abs(sx-ex)+abs(sy-ey))%2!=T%2){ //剪枝
cout << "NO" << endl;
continue;
}
vis[sx][sy] = true;
if(Dfs(sx, sy, 0)) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}