用于平面网格图的 Floyd Warshall 算法
Floyd Warshall Algorithm for a planar grid graph
我有这样的图表:
我这样实现图形数组:
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 算法?
谢谢。
您的图形表示基本上是 adjacency list, for each vertex v= G[i][j]
, you have a list containing the edges the graph is connected to. In your case, the list is made by 4 boolean values - each is indicating if the (i,j)
is connected to (i-1,j),(i+1,j),(i,j-1),(i,j+1)
, so using Floyd-Warshall algorithm with that understanding is pretty straight forward, if looking on the 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|
,这是 O(|V|^2)
- 与在 O(|V|^3)
.
中运行的 Floyd-Warshall 相比
对于这样的稀疏图,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;
}
}
}
}
}
}
}
我有这样的图表:
我这样实现图形数组:
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 算法?
谢谢。
您的图形表示基本上是 adjacency list, for each vertex v= G[i][j]
, you have a list containing the edges the graph is connected to. In your case, the list is made by 4 boolean values - each is indicating if the (i,j)
is connected to (i-1,j),(i+1,j),(i,j-1),(i,j+1)
, so using Floyd-Warshall algorithm with that understanding is pretty straight forward, if looking on the 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|
,这是 O(|V|^2)
- 与在 O(|V|^3)
.
对于这样的稀疏图,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;
}
}
}
}
}
}
}