标签:
题意:
输入一个 N * M的迷宫,这个迷宫里‘S‘代表小狗的位置,‘X‘代表陷阱,‘D’代表门,‘.’代表可行走的地方,小狗每次可以选择往周围的四个方向行走,问这个小狗能否正好T步找到门。
思路:
利用回溯 + 剪枝,这道题剪枝特别重要。
剪枝一:
可以把图看成这样:
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
则假设从点 a(i + j,横纵坐标之和) 走到点 b(i + j) ,如果 a 和 b 的奇偶性相同,那么从 a 到 b 必须是偶数步.如果 a 和 b 的奇偶性不同则走过的步数必须是奇数步。所以 当 (a + b + T)为奇数时一定不能恰好到达。
剪枝二:
如果已经找到答案就没有要继续求解。
剪枝三:
T大于从S到D的最长路径,小于从S到D的最短路径,则无解。
代码:
#include <cstdio> #include <iostream> #include <cstring> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> using namespace std; const int MAXN = 11; char Gra[MAXN][MAXN]; int stepX[] = {0, 0, 1, -1}; int stepY[] = {-1, 1, 0, 0}; int N, M, T; int cnt; int beginX, beginY, endX, endY; int OK; int check(int x, int y) { if(Gra[x][y] == ‘O‘) return 0; // 走到了已经走过的路 if(Gra[x][y] == ‘*‘) return 0; //走出了边界 if(Gra[x][y] == ‘X‘) return 0; //走到了墙 if(cnt > T) return 0; //在此时走的步数已经大于总步数则 return 1; } void backtrack(int x, int y) { if(x == endX && y == endY ) //到达终点 { if(cnt == T) //找到了答案 OK = 1; } else { for(int i = 0; i < 4; i++) //在这点一共有四种选择(状态) { int tx = x + stepX[i]; int ty = y + stepY[i]; if(check(tx, ty)) //检查所选择的状态是否合理 { ++cnt; //记录走过的步数 Gra[tx][ty] = ‘O‘; //标记走过的地方 if(OK) return; //尤为重要的剪枝 ,如果找到答案,就不用继续递归, backtrack(tx, ty); Gra[tx][ty] = ‘.‘; //恢复现场 --cnt; } } } } int main() { //freopen("in.txt","r", stdin); while(~scanf("%d%d%d",&N, &M, &T) && N) { getchar(); beginX = beginY = endX = endY = 0; memset(Gra, ‘*‘, sizeof(Gra)); for(int i = 1; i <= N; i++) { for(int j = 1; j <= M; j++) { scanf("%c",&Gra[i][j]); if(Gra[i][j] == ‘S‘) beginX = i, beginY = j; if(Gra[i][j] == ‘D‘) endX = i, endY = j; } getchar(); } OK = 0; if( (T > M * N) || ( T < (abs(beginX - endX) + abs(beginY - endY)) ) || ( (beginX + beginY + endX + endY + T) & 1 ))//剪枝二、三 { printf("NO\n"); continue; } cnt = 0; Gra[beginX][beginY] = ‘O‘; backtrack(beginX, beginY); if(OK) printf("YES\n"); else printf("NO\n"); } return 0; }
HDU1010 Tempter of the Bone(回溯 + 剪枝)
标签:
原文地址:http://www.cnblogs.com/Ash-ly/p/5398734.html