题目大意:给一个n*m的图,给定起点及目的地,每次往某个方向滑动后只有撞到石头才会停下,且石头会被撞毁,如果出界则不能这样走。问做少滑动多少次能到目的地,且限制了最多滑10次(用来剪枝)(注意,滑动次数不是指走一格算一次,还是从开始滑动到停下才算一次)
题目链接:点击打开链接
分析:用dfs,每次枚举4个方向,若没有停下则一直前进直到停下进入下一次递归,同时记录下被撞到的石头被摧毁,返回时再将此石头恢复就行(利用回溯的思想),若出界则此方向不能走continue就行
直接上代码:
#include<cstdio> //POJ3009 dfs+经典回溯 #include<algorithm> using namespace std; #define Max 20+5 #define Minus_1 -1 int a[Max][Max]; int sx, sy, ex, ey, ans = 11; struct point { int first, second; }p[4] = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } }; void dfs(int x, int y, int step, int turn) { if (step > 10) return; for (int i = 0; i < 4; i++) //枚举4个方向 { int flag = 0; int r = x + p[i].first, v = y + p[i].second; flag++; while (a[r][v] == 0) { r = r + p[i].first; v = v + p[i].second; flag++; } //只要此方向下一格为0,就一直往此方向走 if (a[r][v] == 1 && flag > 1) { a[r][v] = 0; dfs(r - p[i].first, v - p[i].second, step + 1, i); a[r][v] = 1; } if (a[r][v] == Minus_1) continue; if (a[r][v] == 3 && step + 1 < ans) { ans = step + 1; return; } } return; } int main() { int W, H; while (scanf("%d%d", &W, &H)) { if (W == 0 && W == 0) break; ans = 11; memset(a, Minus_1, sizeof(a)); for (int i = 1; i <= H; i++) for (int j = 1; j <= W; j++) { scanf("%d", &a[i][j]); if (a[i][j] == 2) { sx = i, sy = j; } if (a[i][j] == 3) { ex = i, ey = j; } } a[sx][sy] = 0; dfs(sx, sy, 0, 4); printf("%d\n", ans <= 10 ? ans : -1); } return 0; }