📅  最后修改于: 2023-12-03 15:28:08.926000             🧑  作者: Mango
在访问 N * M 网格的所有角落时,我们需要找到一种最短的路径。这个问题可以很方便地建模为图论问题。我们把场景披象成一个有向图,其中由一个格子向相邻格子之间连有向边。因为我们只能走到相邻的格子,所以我们只考虑相邻格子之间相互连边。
对于一个 N * M 的网格,我们可以将每个格子映射到由行、列确定的二元组 (i, j) 。例如,对于一个 3 * 3 的网格,我们将第一行、第二行、第三行的三个格子分别映射到 (1,1)、(1,2)、(1,3)、(2,1)、..、(3,3) 共九个不同的顶点。如果一个格子是合法的,我们就在与它相邻的格子之间连上一条有向边。比如,如果 (1,2) 与 (1,3) 以及 (2,2) 相邻且二者皆非障碍物,则我们从结点 (1,2) 向 (1,3) 以及 (2,2) 分别连边。
// 图的数据结构示意代码
int dir[4][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}};
// 初始化网格
vector<vector<int>> grid(n, vector<int>(m, 0));
// 建图
vector<vector<int>> graph(n*m, vector<int>());
for(int i=0; i<n; i++) {
for(int j=0; j<m; j++) {
for(int k=0; k<4; k++) { // 四个方向
int x = i + dir[k][0], y = j + dir[k][1];
if(x>=0 && x<n && y>=0 && y<m && grid[x][y]==0) {
// (i,j) 到 (x,y) 之间连一条边
graph[i*m+j].push_back(x*m+y);
}
}
}
}
有了上述图的建模,我们可以使用 BFS 算法求解从 (0,0) 出发到达其他所有结点的最短路径。
// BFS 算法求解从 (0,0) 到所有结点的最短路径
vector<int> bfs(int n, int m, vector<vector<int>>& graph) {
int src = 0; // 源结点为左上角
vector<int> dist(n*m, -1); // 到每个点的最短距离
queue<int> q;
dist[src] = 0; q.push(src);
while(!q.empty()) {
int u = q.front(); q.pop();
for(auto& v : graph[u]) {
if(dist[v]==-1) { // 仅对没有访问过的结点进行遍历
dist[v] = dist[u] + 1;
q.push(v);
}
}
}
return dist;
}
注意到对于 BFS 算法,我们初始化了所有点都无法到达的 dist 值为 -1 。因为有些点不可达,所以没有被遍历到的点,在 result 中对应的是 -1 。
#include <bits/stdc++.h>
using namespace std;
int dir[4][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}};
// BFS 算法求解从 (0,0) 到所有结点的最短路径
vector<int> bfs(int n, int m, vector<vector<int>>& graph) {
int src = 0; // 源结点为左上角
vector<int> dist(n*m, -1); // 到每个点的最短距离
queue<int> q;
dist[src] = 0; q.push(src);
while(!q.empty()) {
int u = q.front(); q.pop();
for(auto& v : graph[u]) {
if(dist[v]==-1) { // 仅对没有访问过的结点进行遍历
dist[v] = dist[u] + 1;
q.push(v);
}
}
}
return dist;
}
// 计算最少步骤
int minSteps(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
// 建图
vector<vector<int>> graph(n*m, vector<int>());
for(int i=0; i<n; i++) {
for(int j=0; j<m; j++) {
for(int k=0; k<4; k++) { // 四个方向
int x = i + dir[k][0], y = j + dir[k][1];
if(x>=0 && x<n && y>=0 && y<m && grid[x][y]==0) {
// (i,j) 到 (x,y) 之间连一条边
graph[i*m+j].push_back(x*m+y);
}
}
}
}
// BFS 求解最短路径
vector<int> dist = bfs(n, m, graph);
// 检查所有点是否可达
int ans = 0;
for(auto& row: grid) {
for(auto& cell : row) {
if(cell==0) continue;
int x = cell / m, y = cell % m;
if(dist[cell]==-1) return -1;
else ans = max(ans, dist[cell]);
}
}
return ans;
}
int main() {
vector<vector<int>> grid = {{0,0,0,0,1,1},
{0,1,0,0,1,0},
{0,0,0,1,0,1},
{0,0,0,1,0,0},
{0,1,0,0,0,1},
{1,0,0,0,1,0}};
cout << minSteps(grid) << endl; // 输出 17
return 0;
}