这个题是比较难的宽搜题,之所以难是因为他比以前的这个类似题目多了一个炸弹,增加了题目难度。不过杭电的数据好像不强,也就让很多人可以过了。
刚开始的时候我也只有考虑到时间和炸弹数这两个因素。后来我发现有一个因素我们同样需要考虑就是炸弹炸的地方,好像杭电并没有出这种数据我先出个数据
6 5
S.XX1
X.1X1
XX.X.
XXXXX
XXXXX
XXXDX
这个数据的答案并不是-1,而是17.
我的方法也是比较笨的,个人觉得有点蛮干,我把每条路径的每个位置的炸弹数都保存下来了。所以我的是相对每条路径上的炸弹数,而不是整个的。这样就解决了上面那个问题。
我不知道深搜能不能过,好像时间还挺多的,没试过,如果是深搜的话就简单多了。
这个题还要注意的一点就是已经走过的位置的炸弹和WALL都相当于'.'。
// hdu 2128 mnlm 1.0
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
#include<queue>
struct NODE
{
int x;
int y;
int b;
int t;
int mb[8][8]; //保存每个位置的最小炸弹数
};
queue <NODE> q;
int xy[4][2] =
{
{0, 1},
{0, -1},
{1, 0},
{-1, 0}
};
int N;
int M;
int startx, starty; //S的位置
char map[10][10];
int ans; //最小的时间,初始值为-1
void BFS()
{
ans = -1;
while (!q.empty())
{
q.pop();
}
NODE m;
NODE tt;
m.x = startx;
m.y = starty;
m.b = 0;
m.t = 0;
memset(m.mb, -1, sizeof(m.mb));
m.mb[m.x][m.y] = 0;
q.push(m);
while (!q.empty())
{
m = q.front();
q.pop();
if (ans != -1 &&
m.t + 1 >= ans)
{
continue;
}
int i;
for (i = 0; i < 4; i++)
{
tt.x = m.x + xy[i][0];
tt.y = m.y + xy[i][1];
tt.b = -1;
if (tt.x >= 0 && tt.x < N &&
tt.y >= 0 && tt.y < M)
{
if (map[tt.x][tt.y] == 'D')
{
if (ans == -1 ||
m.t + 1 < ans)
{
ans = m.t + 1;
}
continue;
}
if (m.mb[tt.x][tt.y] > -1 ||
map[tt.x][tt.y] == '.') //已经走过的炸弹和WALL都没有了,相当于'.'
{
tt.t = m.t + 1;
tt.b = m.b;
}
else if (map[tt.x][tt.y] == 'X' &&
m.b > 0)
{
tt.t = m.t + 2;
tt.b = m.b - 1;
}
else if (isdigit(map[tt.x][tt.y]))
{
tt.t = m.t + 1;
tt.b = m.b + map[tt.x][tt.y] - '0';
}/* 这个剪枝有问题
if (tt.b > m.mb[tt.x][tt.y])
{
memcpy(tt.mb, m.mb, 64 * sizeof(int));
tt.mb[tt.x][tt.y] = tt.b;
q.push(tt);
}*/
}
}
}
return;
}
int main()
{
while (1)
{
scanf("%d%d", &N, &M);
if (!N && !M)
{
break;
}
int i;
int j;
for (i = 0; i < N; i++)
{
scanf("%s", map[i]);
for (j = 0; j < M; j++)
{
if (map[i][j] == 'S')
{
startx = i;
starty = j;
}
}
}
BFS();
printf("%d\n", ans);
}
}
再给一些数据吧:
6 6
S1XX3X
XXXXXX
2XXXXX
XXXXXX
XXXXXX
X1XDXX
29
5 3
S..
1X.
XX.
...
XXD
6
5 6
S.XXXX
21..XX
XXXXXX
XXXXXX
3XXXDX
11