📌  相关文章
📜  使用 Floyd Warshall 算法寻找任意两个节点之间的最短路径

📅  最后修改于: 2021-09-22 09:58:47             🧑  作者: Mango

给定一个和两个节点uv ,任务是使用 Floyd Warshall 算法打印 u 和 v 之间的最短路径。

例子:

方法:

  • 这里的主要思想是使用一个矩阵(二维数组),如果任何一对节点的最短路径发生变化,它将跟踪下一个要指向的节点。最初,任意两个节点 u 和 v 之间的最短路径是 v(即从 u -> v 的直接边)。
  • 初始化Next数组
  • Floyd Warshall 算法的修改
  • 这就是我们的if 条件的样子
if(dis[i][j] > dis[i][k] + dis[k][j])
{
    dis[i][j] = dis[i][k] + dis[k][j];
    Next[i][j] = Next[i][k];    
}
  • 为了使用这些节点构建路径,我们将简单地开始遍历节点u ,同时将其值更新为 next[u][v] ,直到我们到达节点v
path = [u]
while u != v:
    u = Next[u][v]
    path.append(u)

下面是上述方法的实现。

C++
// C++ program to find the shortest
// path between any two nodes using
// Floyd Warshall Algorithm.
#include 
using namespace std;
 
#define MAXN 100
// Infinite value for array
const int INF = 1e7;
 
int dis[MAXN][MAXN];
int Next[MAXN][MAXN];
 
// Initializing the distance and
// Next array
void initialise(int V,
                vector >& graph)
{
    for (int i = 0; i < V; i++) {
        for (int j = 0; j < V; j++) {
            dis[i][j] = graph[i][j];
 
            // No edge between node
            // i and j
            if (graph[i][j] == INF)
                Next[i][j] = -1;
            else
                Next[i][j] = j;
        }
    }
}
 
// Function construct the shortest
// path between u and v
vector constructPath(int u,
                        int v)
{
    // If there's no path between
    // node u and v, simply return
    // an empty array
    if (Next[u][v] == -1)
        return {};
 
    // Storing the path in a vector
    vector path = { u };
    while (u != v) {
        u = Next[u][v];
        path.push_back(u);
    }
    return path;
}
 
// Standard Floyd Warshall Algorithm
// with little modification Now if we find
// that dis[i][j] > dis[i][k] + dis[k][j]
// then we modify next[i][j] = next[i][k]
void floydWarshall(int V)
{
    for (int k = 0; k < V; k++) {
        for (int i = 0; i < V; i++) {
            for (int j = 0; j < V; j++) {
 
                // We cannot travel through
                // edge that doesn't exist
                if (dis[i][k] == INF
                    || dis[k][j] == INF)
                    continue;
 
                if (dis[i][j] > dis[i][k]
                                    + dis[k][j]) {
                    dis[i][j] = dis[i][k]
                                + dis[k][j];
                    Next[i][j] = Next[i][k];
                }
            }
        }
    }
}
 
// Print the shortest path
void printPath(vector& path)
{
    int n = path.size();
    for (int i = 0; i < n - 1; i++)
        cout << path[i] << " -> ";
    cout << path[n - 1] << endl;
}
 
// Driver code
int main()
{
 
    int V = 4;
    vector > graph
        = { { 0, 3, INF, 7 },
            { 8, 0, 2, INF },
            { 5, INF, 0, 1 },
            { 2, INF, INF, 0 } };
 
    // Function to initialise the
    // distance and Next array
    initialise(V, graph);
 
    // Calling Floyd Warshall Algorithm,
    // this will update the shortest
    // distance as well as Next array
    floydWarshall(V);
    vector path;
 
    // Path from node 1 to 3
    cout << "Shortest path from 1 to 3: ";
    path = constructPath(1, 3);
    printPath(path);
 
    // Path from node 0 to 2
    cout << "Shortest path from 0 to 2: ";
    path = constructPath(0, 2);
    printPath(path);
 
    // path from node 3 to 2
    cout << "Shortest path from 3 to 2: ";
    path = constructPath(3, 2);
    printPath(path);
 
    return 0;
}


Java
// Java program to find the shortest
// path between any two nodes using
// Floyd Warshall Algorithm.
import java.util.*;
 
class GFG{
 
static final int MAXN = 100;
 
// Infinite value for array
static int INF = (int) 1e7;
 
static int [][]dis = new int[MAXN][MAXN];
static int [][]Next = new int[MAXN][MAXN];
 
// Initializing the distance and
// Next array
static void initialise(int V,
                    int [][] graph)
{
    for(int i = 0; i < V; i++)
    {
    for(int j = 0; j < V; j++)
    {
        dis[i][j] = graph[i][j];
             
        // No edge between node
        // i and j
        if (graph[i][j] == INF)
            Next[i][j] = -1;
        else
            Next[i][j] = j;
    }
    }
}
 
// Function conthe shortest
// path between u and v
static Vector constructPath(int u,
                                    int v)
{
 
    // If there's no path between
    // node u and v, simply return
    // an empty array
    if (Next[u][v] == -1)
        return null;
 
    // Storing the path in a vector
    Vector path = new Vector();
    path.add(u);
     
    while (u != v)
    {
        u = Next[u][v];
        path.add(u);
    }
    return path;
}
 
// Standard Floyd Warshall Algorithm
// with little modification Now if we find
// that dis[i][j] > dis[i][k] + dis[k][j]
// then we modify next[i][j] = next[i][k]
static void floydWarshall(int V)
{
    for(int k = 0; k < V; k++)
    {
    for(int i = 0; i < V; i++)
    {
        for(int j = 0; j < V; j++)
        {
             
            // We cannot travel through
            // edge that doesn't exist
            if (dis[i][k] == INF ||
                dis[k][j] == INF)
                continue;
                 
            if (dis[i][j] > dis[i][k] +
                            dis[k][j])
            {
                dis[i][j] = dis[i][k] +
                            dis[k][j];
                Next[i][j] = Next[i][k];
            }
        }
    }
    }
}
 
// Print the shortest path
static void printPath(Vector path)
{
    int n = path.size();
    for(int i = 0; i < n - 1; i++)
    System.out.print(path.get(i) + " -> ");
    System.out.print(path.get(n - 1) + "\n");
}
 
// Driver code
public static void main(String[] args)
{
    int V = 4;
    int [][] graph = { { 0, 3, INF, 7 },
                    { 8, 0, 2, INF },
                    { 5, INF, 0, 1 },
                    { 2, INF, INF, 0 } };
 
    // Function to initialise the
    // distance and Next array
    initialise(V, graph);
 
    // Calling Floyd Warshall Algorithm,
    // this will update the shortest
    // distance as well as Next array
    floydWarshall(V);
    Vector path;
 
    // Path from node 1 to 3
    System.out.print("Shortest path from 1 to 3: ");
    path = constructPath(1, 3);
    printPath(path);
 
    // Path from node 0 to 2
    System.out.print("Shortest path from 0 to 2: ");
    path = constructPath(0, 2);
    printPath(path);
 
    // Path from node 3 to 2
    System.out.print("Shortest path from 3 to 2: ");
    path = constructPath(3, 2);
    printPath(path);
}
}
 
// This code is contributed by Amit Katiyar


Python3
# Python3 program to find the shortest
# path between any two nodes using
# Floyd Warshall Algorithm.
 
# Initializing the distance and
# Next array
def initialise(V):
    global dis, Next
 
    for i in range(V):
        for j in range(V):
            dis[i][j] = graph[i][j]
 
            # No edge between node
            # i and j
            if (graph[i][j] == INF):
                Next[i][j] = -1
            else:
                Next[i][j] = j
 
# Function construct the shortest
# path between u and v
def constructPath(u, v):
    global graph, Next
     
    # If there's no path between
    # node u and v, simply return
    # an empty array
    if (Next[u][v] == -1):
        return {}
 
    # Storing the path in a vector
    path = [u]
    while (u != v):
        u = Next[u][v]
        path.append(u)
 
    return path
 
# Standard Floyd Warshall Algorithm
# with little modification Now if we find
# that dis[i][j] > dis[i][k] + dis[k][j]
# then we modify next[i][j] = next[i][k]
def floydWarshall(V):
    global dist, Next
    for k in range(V):
        for i in range(V):
            for j in range(V):
                 
                # We cannot travel through
                # edge that doesn't exist
                if (dis[i][k] == INF or dis[k][j] == INF):
                    continue
                if (dis[i][j] > dis[i][k] + dis[k][j]):
                    dis[i][j] = dis[i][k] + dis[k][j]
                    Next[i][j] = Next[i][k]
 
# Print the shortest path
def printPath(path):
    n = len(path)
    for i in range(n - 1):
        print(path[i], end=" -> ")
    print (path[n - 1])
 
# Driver code
if __name__ == '__main__':
    MAXM,INF = 100,10**7
    dis = [[-1 for i in range(MAXM)] for i in range(MAXM)]
    Next = [[-1 for i in range(MAXM)] for i in range(MAXM)]
 
    V = 4
    graph = [ [ 0, 3, INF, 7 ],
            [ 8, 0, 2, INF ],
            [ 5, INF, 0, 1 ],
            [ 2, INF, INF, 0 ] ]
 
    # Function to initialise the
    # distance and Next array
    initialise(V)
 
    # Calling Floyd Warshall Algorithm,
    # this will update the shortest
    # distance as well as Next array
    floydWarshall(V)
    path = []
 
    # Path from node 1 to 3
    print("Shortest path from 1 to 3: ", end = "")
    path = constructPath(1, 3)
    printPath(path)
 
    # Path from node 0 to 2
    print("Shortest path from 0 to 2: ", end = "")
    path = constructPath(0, 2)
    printPath(path)
 
    # Path from node 3 to 2
    print("Shortest path from 3 to 2: ", end = "")
    path = constructPath(3, 2)
    printPath(path)
 
    # This code is contributed by mohit kumar 29


C#
// C# program to find the shortest
// path between any two nodes using
// Floyd Warshall Algorithm.
using System;
using System.Collections.Generic;
 
class GFG{
 
static readonly int MAXN = 100;
 
// Infinite value for array
static int INF = (int)1e7;
 
static int [,]dis = new int[MAXN, MAXN];
static int [,]Next = new int[MAXN, MAXN];
 
// Initializing the distance and
// Next array
static void initialise(int V,
                       int [,] graph)
{
    for(int i = 0; i < V; i++)
    {
        for(int j = 0; j < V; j++)
        {
            dis[i, j] = graph[i, j];
                 
            // No edge between node
            // i and j
            if (graph[i, j] == INF)
                Next[i, j] = -1;
            else
                Next[i, j] = j;
        }
    }
}
 
// Function conthe shortest
// path between u and v
static List constructPath(int u, int v)
{
     
    // If there's no path between
    // node u and v, simply return
    // an empty array
    if (Next[u, v] == -1)
        return null;
 
    // Storing the path in a vector
    List path = new List();
    path.Add(u);
     
    while (u != v)
    {
        u = Next[u, v];
        path.Add(u);
    }
    return path;
}
 
// Standard Floyd Warshall Algorithm
// with little modification Now if we find
// that dis[i,j] > dis[i,k] + dis[k,j]
// then we modify next[i,j] = next[i,k]
static void floydWarshall(int V)
{
    for(int k = 0; k < V; k++)
    {
        for(int i = 0; i < V; i++)
        {
            for(int j = 0; j < V; j++)
            {
                 
                // We cannot travel through
                // edge that doesn't exist
                if (dis[i, k] == INF || 
                    dis[k, j] == INF)
                    continue;
                    
                if (dis[i, j] > dis[i, k] +
                                dis[k, j])
                {
                    dis[i, j] = dis[i, k] + 
                                dis[k, j];
                    Next[i, j] = Next[i, k];
                }
            }
        }
    }
}
 
// Print the shortest path
static void printPath(List path)
{
    int n = path.Count;
     
    for(int i = 0; i < n - 1; i++)
        Console.Write(path[i] + " -> ");
        
    Console.Write(path[n - 1] + "\n");
}
 
// Driver code
public static void Main(String[] args)
{
    int V = 4;
    int [,] graph = { { 0, 3, INF, 7 },
                      { 8, 0, 2, INF },
                      { 5, INF, 0, 1 },
                      { 2, INF, INF, 0 } };
 
    // Function to initialise the
    // distance and Next array
    initialise(V, graph);
 
    // Calling Floyd Warshall Algorithm,
    // this will update the shortest
    // distance as well as Next array
    floydWarshall(V);
    List path;
 
    // Path from node 1 to 3
    Console.Write("Shortest path from 1 to 3: ");
    path = constructPath(1, 3);
    printPath(path);
 
    // Path from node 0 to 2
    Console.Write("Shortest path from 0 to 2: ");
    path = constructPath(0, 2);
    printPath(path);
 
    // Path from node 3 to 2
    Console.Write("Shortest path from 3 to 2: ");
    path = constructPath(3, 2);
    printPath(path);
}
}
 
// This code is contributed by Amit Katiyar


Javascript


输出:
Shortest path from 1 to 3: 1 -> 2 -> 3
Shortest path from 0 to 2: 0 -> 1 -> 2
Shortest path from 3 to 2: 3 -> 0 -> 1 -> 2

复杂度分析:

  • Floyd Warshall 算法的时间复杂度为O(V 3 )
  • 查找最短路径的时间复杂度是每个查询O(V)

注意:当您的图形包含几百个顶点并且您需要回答与最短路径相关的多个查询时,使用 Floyd Warshall 算法会很有效。

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程