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:[email protected] * 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; }