算法竞赛入门经典177页,bfs,经典
题目意思:
有一个 n * m 大小的矩阵, 矩阵 只要数字 0 或者 1,0 表示空白可以走,1 表示有障碍物。
现在,要求 从起点 s(1, 1) 走到终点 t (n, m), 这两点都是空白。 每次走,可以连续穿过 k 个障碍物。
问,从 s(1, 1) 到 t (n, m) 至少走多少步。
本题要点:
1、这里的 “连续穿过 k 个障碍物” , 不一定是只要沿着一个方向走,这里的走可以是拐弯的走法。
所谓的拐弯,比如,从 点 (1, 1) ,右,下,下,左,就到达了点(3, 1)
2、如果没有k的限制,就是 bfs 的水题。加了限制,可以在原来二维 的vis数组加上第3维 layer。
vis[x][y][layer] 表示到达这一点 (x, y),已经连续穿过了layer个1。
首先,layer > 0 的时候,表示当前点(x, y) 是 mp[x][y] 是 1(如果 当前点是 0, 那么 layer 只能是 0);
vis[x][y][layer] == false, 进入到 点 (x, y) , 表示 从 之前的某点(假设点 (x0, y0)), 连续走了 layer 个 1, 才走到 点(x0, y0)。
3、 vis[x][y][layer] == true, 就不需要进入这点了。 已经有的点 (叫做 “早点” 吧) , “早点” 更早就进入队列了,
并且尝试了 连续走了 layer 个1 才走到了点 (x, y)。
所以,其他的点 连续走了 layer 个1 才走到了点 (x, y), 就不要再走了,因为有 “早点” 已经尝试过 了。
4、 代码是这位老哥的 点这里
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int MaxN = 25;
int n, m, k, T;
bool vis[MaxN][MaxN][MaxN];
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
int mp[MaxN][MaxN];
int cnt;
struct node
{
int x, y;
int step;
int layer;
node(int _x = 1, int _y = 1, int _step = 0, int _layer = 0)
:x(_x), y(_y), step(_step), layer(_layer)
{}
};
bool check(int x, int y)
{
return x >= 1 && x <= n && y >= 1 && y <= m;
}
void bfs()
{
queue<node> q;
memset(vis, false, sizeof vis);
node s(1, 1, 0, 0);
node t(n, m);
q.push(s);
vis[1][1][0] = true;
while(!q.empty())
{
node now = q.front();q.pop();
if(now.x == t.x && now.y == t.y)
{
printf("%d\n", now.step);
return;
}
int x, y, layer;
for(int i = 0; i < 4; ++i)
{
x = now.x + dx[i], y = now.y + dy[i], layer = now.layer;
if(mp[x][y])
{
layer++;
}else{
layer = 0;
}
if(layer <= k && check(x, y) && !vis[x][y][layer])
{
q.push(node(x, y, now.step + 1, layer));
vis[x][y][layer] = true;
}
}
}
printf("-1\n");
}
int main()
{
scanf("%d", &T);
while(T--)
{
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
{
scanf("%d", &mp[i][j]);
}
bfs();
}
return 0;
}
/*
3
2 5
0
0 1 0 0 0
0 0 0 1 0
4 6
1
0 1 1 0 0 0
0 0 1 0 1 1
0 1 1 1 1 0
0 1 1 1 0 0
2 2
0
0 1
1 0
*/
/*
7
10
-1
*/