一、题意
有一个巡逻机器人要从一个n*m的网格的左上角走到右上角,网格中0为空地,1为障碍物。
该机器人具备连续通过k个障碍物的能力,求最短路径长度。
二、解析
最短路径考虑bfs。同样需要确定bfs的“状态点”如何定义。
考虑到该机器人穿障碍物的能力(在障碍物中也可以拐弯),因此需要把它该能力的剩余“能量点”(初始为k)作为状态之一。注意作为状态后vis将要变成3维。
三、代码
#include <iostream> #include <queue> #include <cstring> using namespace std; const int maxn = 20 + 5, maxm = 20 + 5, maxk = 20 + 5; const int Fx[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; struct node { int x, y, dist, remain; node(int x, int y, int dist, int remain) : x(x), y(y), dist(dist), remain(remain) {} }; int kase, n, m, k; int a[maxn][maxm], vis[maxn][maxm][maxk]; void bfs(int x0, int y0) { queue<node> que; que.push(node(x0, y0, 0, k)), vis[x0][y0][k] = 1; int ans = -1; while(!que.empty()) { node u = que.front(); que.pop(); // cout << "u=(" << u.x << "," << u.y << ")" << endl; if(u.x == n - 1 && u.y == m - 1) { ans = u.dist; break; } for(int i = 0; i < 4; i ++) { int nx = u.x + Fx[i][0], ny = u.y + Fx[i][1]; // cout << "v=(" << nx << "," << ny << ")" << endl; if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue; if(a[nx][ny] == 1) { if(vis[nx][ny][u.remain - 1] || u.remain - 1 < 0) continue; que.push(node(nx, ny, u.dist + 1, u.remain - 1)); vis[nx][ny][u.remain - 1] = 1; } else { if(vis[nx][ny][k]) continue; que.push(node(nx, ny, u.dist + 1, k)); vis[nx][ny][k] = 1; } } } cout << ans << endl; } int main() { cin >> kase; while(kase --) { cin >> n >> m >> k; for(int i = 0; i < n; i ++) for(int j = 0; j < m; j ++) cin >> a[i][j]; memset(vis, 0, sizeof(vis)); bfs(0, 0); } }
四、归纳
- 只要抓准了bfs的状态点是什么,bfs的题目基本就能迎刃而解了