2015年4月27日。
hdoj1010,题目大意给你N * M(1 < N, M < 7)的迷宫,从S到达D,问能否完成在T(T < 50)步内完成,能则YES,否则NO, ‘.’表示能走,‘X’表示不能走。多组数据0 0 0 时输入结束。 明显的搜索,而且是深搜。但如果你不加剪枝估计是过不了。这个题有几个堪称神奇的剪枝。
剪枝1:如果‘.’个数比T小,那S一定不能到达D;
剪枝2:可以通过S,D(S是指深搜的过程中当前的位置)的位置算出S到D需要奇数步还是偶数步。假设S(i1,j1),D(i2,j2),那么abs(i1 - i2) + abs(j1 - j2)为奇数数,S到D一定是奇数步(不论你怎么绕,读者可以画图试一试),反之S到D一定是偶数步。若还需要的步数T- step加上这个奇数步或者偶数步为奇数,则此路径是行不通的。
剪枝3:如果当前搜搜的步数step大于T,则此条路径以后不论怎么走,总步数一定大于T,这条路径直接返回false。
剪枝4:若深搜的过程中当前位置等于D,则判断step步数是否等于T,若等于则返回true,否则这条路径以后不论怎么走,步数又会超过T,此时就直接返回false即可。
贴下代码供大家参考。
/*
* Author : Roye_Bao
* Time : 2015-4-4
* Id : Royecode
* Email:Royecode@163.com
* Language : C / C++
*/
#include <iostream>
#include <cmath>
#define Pii pair <int, int>
using namespace std;
char maze[8][8];
int n, m, t;
int dir[4][2] = {-1, 0, 0, 1, 1, 0, 0, -1}; //四个方向
bool dfs(Pii S, Pii D, int step, int cnt)
{
if(S == D) return step == t; //剪枝4
if(step > t) return false; //剪枝3
if(cnt < t - step) return false; //剪枝1
if((abs(S.first - D.first) + abs(S.second - D.second) + t - step) % 2) return false; //剪枝2
for(int i = 0; i < 4; ++i)
{
int dx = S.first + dir[i][0], dy = S.second + dir[i][1];
if(dx >= 0 && dx < n && dy >= 0 && dy < m && maze[dx][dy] != 'X' && maze[dx][dy] != 'S')
{
maze[dx][dy] = 'X';
if(dfs(Pii(dx, dy), D, step + 1, cnt - 1)) return true;
maze[dx][dy] = '.';
}
}
return false;
}
int main()
{
while(~scanf("%d%d%d", &n, &m, &t), n, m, t)
{
Pii S, D;
int cnt = 1;
getchar();
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < m; ++j)
{
maze[i][j] = getchar();
if(maze[i][j] == 'S') S = Pii(i, j);
else if(maze[i][j] == 'D') D = Pii(i, j);
else if(maze[i][j] == '.') cnt++;
}
getchar();
}
printf(dfs(S, D, 0, cnt)? "YES\n": "NO\n");
}
return 0;
}