http://acm.hdu.edu.cn/showproblem.php?pid=1010
大神题解报告http://acm.hdu.edu.cn/forum/read.php?tid=6158
- 关于剪枝,没有剪枝的搜索不太可能,这题老刘上课的时候讲过两个剪枝,一个是奇偶剪枝,一个是路径剪枝
- 奇偶剪枝:
- 把矩阵标记成如下形式:
- 0,1,0,1,0
- 1,0,1,0,1
- 0,1,0,1,0
- 1,0,1,0,1
- 很明显,如果起点在0 而终点在1 那显然 要经过奇数步才能从起点走到终点,依次类推,奇偶相同的偶数步,奇偶不同的奇数步
- 在读入数据的时候就可以判断,并且做剪枝,当然做的时候并不要求把整个矩阵0,1刷一遍,读入的时候起点记为(Si,Sj) 终点记为(Di,Dj) 判断(Si+Sj) 和 (Di+Dj) 的奇偶性就可以了
- 路径剪枝:
- 矩阵的大小是N*M 墙的数量记为wall 如果能走的路的数量 N*M - wall 小于时间T,就是说走完也不能到总的时间的,这显然是错误的,可以直接跳出了
#include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <cmath> using namespace std; char map[30][30]; int vis[30][30]; int dx[] = {0, 1, 0, -1}; int dy[] = {1, 0, -1, 0}; int n, m, t, a, b, flag; struct point { int x, y, step; } st; void dfs(point st); int main() { //freopen("1.txt", "w", stdout); while (~scanf("%d%d%d", &m, &n, &t) && (n + m + t != 0)) { int wall = 0; flag = 0; memset(map, 0, sizeof(map)); for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { scanf(" %c", &map[i][j]); if (map[i][j] == 'S') { memset(vis, 0, sizeof(vis)); st.x = i; st.y = j; st.step = 0; } if (map[i][j] == 'D') { a = i; b = j; } if (map[i][j] == 'X') { wall++; } } } dfs(st); if (flag) { printf("YES "); } else { printf("NO "); } } return 0; } void dfs(point st) { int xx = abs(a - st.x), yy = abs(b - st.y), tt = t - st.step;; //printf("x=%d,y=%d,t=%d,%d ", st.x, st.y, tt, (tt - xx - yy)); if(flag == 1) { return; //不加这个会TLE } if (tt < 0 || ((tt - xx - yy) % 2 != 0)) { return; } else { if (tt == 0) { if (map[st.x][st.y] == 'D') { flag = 1; return; } else { return; } } else for (int i = 0; i < 4; i++) { point next = st; next.x = st.x + dx[i], next.y = st.y + dy[i]; int nx = next.x, ny = next.y; if ((map[nx][ny] == '.' || map[nx][ny] == 'D') && nx > 0 && nx <= m && ny > 0 && ny <= n && !vis[nx][ny]) { next.step++; vis[nx][ny] = 1; dfs(next); vis[nx][ny] = 0; } } } }