题目大意:给一个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;
}