【问题标题】:Floyd Warshall Algorithm for a planar grid graph平面网格图的 Floyd Warshall 算法
【发布时间】:2015-09-19 15:50:28
【问题描述】:

我有一个这样的图表:

我实现了这样的图形数组:

G[i][j][k]

K只有 4 个单元格,它显示顶点是否连接到它的四个相邻顶点。例如:

G[1][1][0] = 0 
G[1][1][1] = 1 
G[1][1][2] = 1 
G[1][1][3] = 0

表示顶点(1, 1)连接了2个顶点。

我知道用于正常类型图的 Floyd Warshall 算法。 但是我怎样才能为这种图实现 Flyod Warshall 算法呢?

谢谢。

【问题讨论】:

  • 为什么这是不同的“类型”图表。它肯定只是一个没有多重边的未加权图(一个简单的图)。对于最短路径计算,甚至可能有比 Floyd-Warshall 更简单或更快的算法。事实上,肯定有——首先是平面的。
  • @gilleain 是对的。不同的不是图,而是用来表示邻接关系的数据结构
  • @gilleain This type of graph 被称为grid graph,它们通常比一般图表更容易处理。
  • @gilleain 渐近地说似乎不太可能,因为平面图的线性时间算法可以解决与 Dijkstra 算法相同的问题。
  • Link to the algorithm David mentioned,理论上倾向于。

标签: c++ algorithm graph shortest-path floyd-warshall


【解决方案1】:

您的图形表示基本上是一个adjacency list,对于每个顶点v= G[i][j],您都有一个包含图形连接到的边的列表。在您的情况下,该列表由 4 个布尔值组成 - 每个都指示 (i,j) 是否连接到 (i-1,j),(i+1,j),(i,j-1),(i,j+1),因此使用具有这种理解的 Floyd-Warshall 算法非常简单,如果查看 wikipedia pseudo code

1 let dist be a |V| × |V| array of minimum distances initialized to ∞ (infinity)
2 for each vertex v
3    dist[v][v] ← 0
4 for each edge (u,v)
5    dist[u][v] ← w(u,v)  // the weight of the edge (u,v)
6 for k from 1 to |V|
7    for i from 1 to |V|
8       for j from 1 to |V|
9          if dist[i][j] > dist[i][k] + dist[k][j] 
10             dist[i][j] ← dist[i][k] + dist[k][j]
11         end if

主要区别在于第 4-5 行,其中:

for each edge(u,v):

其实是

for each x=0,1,...,n-1
   for each y=0,1,...,m-1
       for each i=0,1,2,3:
             //if G[x][y][y] == 1 : it's an edge

另请注意,在您的图中,最大分支因子(连接到节点的边数)为 4。这意味着图中的最大边数为 |E| <= 4|V|
由于您的图不是定向的,因此通过从每个节点执行 BFS 可以更有效地找到所有最短路径,这将花费 O(|V|*(|E|+|V|)) 时间,但由于 |E| <= 4|V|,这是 @ 987654333@ - 与在 O(|V|^3) 中运行的 Floyd-Warshall 相比。

【讨论】:

    【解决方案2】:

    Floyd-Warshall 算法对于这种稀疏图来说效率非常低。该图是稀疏的,因为每个顶点连接到的其他顶点不超过 4 个。在稠密图中,一个顶点最多可以连接到 N-1 个其他顶点,其中 N 是图中的顶点数。这就是 Floyd-Warshall 算法或多或少有效的地方,但是,如果您不需要每对顶点之间的最短路径或查找负长度循环,请考虑使用优先级队列来查找源和之间的最短路径所有其他顶点:https://en.wikipedia.org/wiki/Dijkstra's_algorithm#Using_a_priority_queue。如果图中每条边的权重相等(未加权图),甚至可以使用广度优先搜索。

    如果您仍然希望您的网格使用 Floyd-Warshall 算法,这里就是。考虑网格是N by M,索引从 1 开始,因此网格中的最大条目是 G[N][M][...]。那么 Floyd-Warshall 算法将是:

    // edge offsets
    const int offs[4][2] = {
        {-1, 0}, {0, 1}, {1, 0}, {0, -1}
    };
    const int INF_DIST = 1e9;
    int D[N+1][M+1][N+1][M+1];
    //// Initialize weights to infinity
    // For each source row and column (i,j)
    for(int i=1; i<=N; i++) {
        for(int j=1; j<=M; j++) {
            // For each destination row and column (k,l)
            for(int k=1; k<=N; k++) {
                for(int l=1; l<=M; l++) {
                    D[i][j][k][l] = INF_DIST;
                }
            }
        }
    }
    //// Mark edges of the graph
    // For each row
    for(int i=1; i<=N; i++) {
        // For each column
        for(int j=1; j<=M; j++) {
            // For each of the directions: up(k=0), right(k=1), down(k=2) and left(k=3)
            for(int k=0; k<=3; k++) {
                if(G[i][j][k] == 0) {
                    // Don't add this edge to the distance matrix
                    //   if the edge is not in the grid graph
                    continue;
                }
                // Calculate (r, c) as the coordinates of the vertex one step 
                //   in the direction k
                int r = i + offs[k][0];
                int c = j + offs[k][1];
                if(1<=r && r <= N && 1<=c && c<=M) {
                    // Only add the edge (if exists) in case (r, c) is within the grid
                    D[i][j][r][c] = G[i][j][k];
                }
            }
        }
    }
    //// Find shortest paths between each pair of vertices
    // For each intermediate vertex (k,l)
    for(k=1; k<=N; k++) {
        for(l=1; l<=M; l++) {
            // For each source vertex (i,j)
            for(int i=1; i<=N; i++) {
                for(int j=1; j<=M; j++) {
                    // For each destination vertex (r,c)
                    for(int r=1; r<=N; r++) {
                        for(int c=1; c<=M; c++) {
                            // Apply the triangle rule
                            int alternative = D[i][j][k][l] + D[k][l][r][c];
                            if(alternative < D[i][j][r][c]) {
                                D[i][j][r][c] = alternative;
                            }
                        }
                    }
                }
            }
        }
    }
    

    【讨论】:

    • 你能解释一下所涉及的循环吗?为什么在权重初始化中需要 4 个循环?因为图 i 和 j 是行和列 wat 是 k?你能解释一下吗
    • @user1234,我添加了代码 cmets。如果还有什么不清楚的地方,请告诉我。
    • 你能解释一下边缘偏移吗
    • 还有 int r = i + offs[k][0]; int c = j + offs[k][1]; if(1
    • @user1234,我也添加了 cmets。
    猜你喜欢
    • 2018-11-11
    • 1970-01-01
    • 1970-01-01
    • 2016-01-18
    • 1970-01-01
    • 2011-02-10
    • 2014-06-28
    • 2012-06-02
    • 2017-09-12
    相关资源
    最近更新 更多