在 2D 图中查找源的最短路径

大多数情况下,我们需要找出从单一来源到所有其他节点或 2D 图中特定节点的最短路径。比如说:我们想知道一个骑士到达棋盘中某个方格需要多少动作,或者我们有一个阵列,其中一些细胞被阻挡,我们必须找出从一个细胞到另一个细胞的最短路径。我们只能水平和垂直移动。甚至对角线移动也是可能的。对于这些情况,我们可以转换节点中的方块或单元格,并使用 BFS 轻松解决这些问题。现在我们的访问父级级别将是 2D 数组。对于每个节点,我们将考虑所有可能的移动。要查找到特定节点的距离,我们还会检查是否已到达目的地。

还有一个叫做方向阵列的东西。这将简单地存储我们可以去的所有可能的方向组合。让我们说,对于水平和垂直移动,我们的方向数组将是:

+----+-----+-----+-----+-----+
| `dx` |  1  |  -1 |  0  |  0  |
+----+-----+-----+-----+-----+
| `dy` |  0  |   0 |  1  |  -1 |
+----+-----+-----+-----+-----+

这里 dx 表示在 x 轴上移动而 dy 表示在 y 轴上移动。这部分也是可选的。你也可以单独编写所有可能的组合。但使用方向数组处理它更容易。对角线移动或骑士移动可以有更多甚至不同的组合。

我们需要记住的另一部分是:

  • 如果任何一个单元被阻塞,对于每个可能的移动,我们将检查该单元是否被阻塞。
  • 我们还将检查我们是否超出了界限,即我们已越过数组边界。
  • 将给出行数和列数。

我们的伪代码将是:

Procedure BFS2D(Graph, blocksign, row, column):
for i from 1 to row
    for j from 1 to column
        visited[i][j] := false
    end for
end for
visited[source.x][source.y] := true
level[source.x][source.y] := 0
Q = queue()
Q.push(source)
m := dx.size
while Q is not empty
    top := Q.pop
    for i from 1 to m
        temp.x := top.x + dx[i]
        temp.y := top.y + dy[i]
        if temp is inside the row and column and top doesn't equal to blocksign
            visited[temp.x][temp.y] := true
            level[temp.x][temp.y] := level[top.x][top.y] + 1
            Q.push(temp)
        end if
    end for
end while
Return level

正如我们之前讨论的那样,BFS 仅适用于未加权的图形。对于加权图,我们需要 Dijkstra 的算法。对于负边缘周期,我们需要 Bellman-Ford 的算法。该算法再次是单源最短路径算法。如果我们需要找出从每个节点到所有其他节点的距离,我们需要 Floyd-Warshall 的算法。