题意:
给一个图,由障碍和空地组成,一块石头可以在上面往一个方向滑动,只能沿着x,y方向滑动,并且那个方向上第一个地方不能是障碍物,石头滑动直到碰到障碍停止,并且消掉障碍物,或者滑出边界,这时候算游戏失败,给出起点和终点,问石头能否在十步之内到达终点,能的话最小步数是多少.
思路:
题目很简单,只需要模拟dfs就可以,注意走过的点可以重新走,因为图是在变化的,建图的时候可以全部初始化为-1,这样判断边界比较简单.但是只是模拟的话会超时,这时候需要剪枝,题目让求最小不熟,可以设定一个变量记录当前最小步数,初始化为11(因为题目要求10步及以内),若dfs时步数大于当前最小步数则退出,可以省去很多不必要的搜索.
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[25][25];
int n, m;
int mi;
int gx, gy;
int next[4][2] = {{1, 0}, {0, 1}, {0, -1}, { -1, 0}};
void dfs(int x, int y, int step)
{
int i;
if(step>mi)return; //如果当前搜索步数大于当前最小步数了, 就不必要搜索.
for (i = 0; i < 4; i++)
{
int nx, ny;
nx = x + next[i][0];
ny = y + next[i][1];
while (a[nx][ny] != -1 && a[nx][ny] != 1) //判断第一个地方是否是边界或障碍
{
if (a[nx][ny] == 3)
{
if (step < mi)
{
mi = step;
}
break;
}
nx += next[i][0];
ny += next[i][1];
if (a[nx][ny] != 0)
{
if (a[nx][ny] == -1)
{
break;
}
if (a[nx][ny] == 1)
{
a[nx][ny] = 0;
nx -= next[i][0];
ny -= next[i][1];
dfs(nx, ny, step + 1);
nx += next[i][0];
ny += next[i][1];
a[nx][ny] = 1; //还原图,因为接下来的操作和这一步是并列的,互不影响.
break;
}
if (a[nx][ny] == 3)
{
if (step < mi)
{
mi = step;
}
return;
}
}
}
}
return;
}
int main()
{
while (~scanf("%d%d", &m, &n))
{
if (n == m && n == 0)
{
break;
}
memset(a, -1, sizeof(a)); //初始化-1,建图之后-1的地方自然就是边界
memset(book, 0, sizeof(book));
int i, j;
mi = 11; //初始化
int sx, sy;
for (i = 1; i <= n; i++)
{
for (j = 1; j <= m; j++)
{
scanf("%d", &a[i][j]);
if (a[i][j] == 2)
{
sx = i;
sy = j;
}
if (a[i][j] == 3)
{
gx = i;
gy = j;
}
}
}
dfs(sx, sy, 1);
if (mi <= 10)
{
printf("%d\n", mi);
}
else
{
printf("-1\n");
}
}
return 0;
}