📜  最短路径更快算法

📅  最后修改于: 2021-05-06 18:38:41             🧑  作者: Mango

先决条件: Bellman-Ford算法

给定具有V个顶点, E个边缘和一个源顶点S的向加权图。任务是找到从源顶点到给定图中所有其他顶点的最短路径。

例子:

方法:最短路径更快算法基于Bellman-Ford算法,其中每个顶点都用于松弛其相邻顶点,但在SPF算法中,仅保留顶点队列,并且仅当该顶点松弛时才将顶点添加到队列中。重复此过程,直到没有更多的顶点可以放宽为止。
可以执行以下步骤来计算结果:

  1. 创建一个数组d [],以存储所有顶点到源顶点的最短距离。除d [S] = 0(其中S为源顶点)外,通过无穷大初始化此数组。
  2. 创建队列Q并在其中推送起始源顶点。
    • 当Queue不为空时,对图形中的每个边(u,v)执行以下操作
      • 如果d [v]> d [u] +边的权重(u,v)
      • d [v] = d [u] +边的权重(u,v)
      • 如果顶点v在队列中不存在,则将顶点v推入队列。

注意:松弛”一词表示更新与顶点v连接的所有顶点的成本,如果可以通过包含通过顶点v的路径来改善这些成本的话。从最短路径的估计值与不是为压缩而设计的螺旋拉伸弹簧的长度之间的类比可以更好地理解这一点。最初,最短路径的成本被高估了,就像延伸的弹簧一样。当找到更短的路径时,估计的成本会降低,弹簧会放松。最终,找到了最短的路径(如果存在的话),并且弹簧已经松弛到其静止长度。

下面是上述方法的实现:

C++
// C++ implementation of SPFA
  
#include 
using namespace std;
  
// Graph is stored as vector of vector of pairs
// first element of pair store vertex
// second element of pair store weight
vector > graph[100000];
  
// Function to add edges in the graph
// connecting a pair of vertex(frm) and weight
// to another vertex(to) in graph
void addEdge(int frm, int to, int weight)
{
  
    graph[frm].push_back({ to, weight });
}
  
// Function to print shortest distance from source
void print_distance(int d[], int V)
{
    cout << "Vertex \t\t Distance"
         << " from source" << endl;
  
    for (int i = 1; i <= V; i++) {
        printf("%d \t\t %d\n", i, d[i]);
    }
}
  
// Function to compute the SPF algorithm
void shortestPathFaster(int S, int V)
{
    // Create array d to store shortest distance
    int d[V + 1];
  
    // Boolean array to check if vertex
    // is present in queue or not
    bool inQueue[V + 1] = { false };
  
    // Initialize the distance from source to
    // other vertex as INT_MAX(infinite)
    for (int i = 0; i <= V; i++) {
        d[i] = INT_MAX;
    }
    d[S] = 0;
  
    queue q;
    q.push(S);
    inQueue[S] = true;
  
    while (!q.empty()) {
  
        // Take the front vertex from Queue
        int u = q.front();
        q.pop();
        inQueue[u] = false;
  
        // Relaxing all the adjacent edges of
        // vertex taken from the Queue
        for (int i = 0; i < graph[u].size(); i++) {
  
            int v = graph[u][i].first;
            int weight = graph[u][i].second;
  
            if (d[v] > d[u] + weight) {
                d[v] = d[u] + weight;
  
                // Check if vertex v is in Queue or not
                // if not then push it into the Queue
                if (!inQueue[v]) {
                    q.push(v);
                    inQueue[v] = true;
                }
            }
        }
    }
  
    // Print the result
    print_distance(d, V);
}
  
// Driver code
int main()
{
    int V = 5;
    int S = 1;
  
    // Connect vertex a to b with weight w
    // addEdge(a, b, w)
  
    addEdge(1, 2, 1);
    addEdge(2, 3, 7);
    addEdge(2, 4, -2);
    addEdge(1, 3, 8);
    addEdge(1, 4, 9);
    addEdge(3, 4, 3);
    addEdge(2, 5, 3);
    addEdge(4, 5, -3);
  
    // Calling shortestPathFaster function
    shortestPathFaster(S, V);
  
    return 0;
}


Java
// Java implementation of SPFA
import java.util.*;
  
class GFG
{
    static class pair
    { 
        int first, second; 
        public pair(int first, int second) 
        { 
            this.first = first; 
            this.second = second; 
        } 
    }
      
// Graph is stored as vector of vector of pairs
// first element of pair store vertex
// second element of pair store weight
static Vector []graph = new Vector[100000];
  
// Function to add edges in the graph
// connecting a pair of vertex(frm) and weight
// to another vertex(to) in graph
static void addEdge(int frm, int to, int weight)
{
  
    graph[frm].add(new pair( to, weight ));
}
  
// Function to print shortest distance from source
static void print_distance(int d[], int V)
{
    System.out.print("Vertex \t\t Distance"
        + " from source" +"\n");
  
    for (int i = 1; i <= V; i++) 
    {
        System.out.printf("%d \t\t %d\n", i, d[i]);
    }
}
  
// Function to compute the SPF algorithm
static void shortestPathFaster(int S, int V)
{
    // Create array d to store shortest distance
    int []d = new int[V + 1];
  
    // Boolean array to check if vertex
    // is present in queue or not
    boolean []inQueue = new boolean[V + 1];
  
    // Initialize the distance from source to
    // other vertex as Integer.MAX_VALUE(infinite)
    for (int i = 0; i <= V; i++) 
    {
        d[i] = Integer.MAX_VALUE;
    }
    d[S] = 0;
  
    Queue q = new LinkedList<>();
    q.add(S);
    inQueue[S] = true;
  
    while (!q.isEmpty())
    {
  
        // Take the front vertex from Queue
        int u = q.peek();
        q.remove();
        inQueue[u] = false;
  
        // Relaxing all the adjacent edges of
        // vertex taken from the Queue
        for (int i = 0; i < graph[u].size(); i++)
        {
  
            int v = graph[u].get(i).first;
            int weight = graph[u].get(i).second;
  
            if (d[v] > d[u] + weight) 
            {
                d[v] = d[u] + weight;
  
                // Check if vertex v is in Queue or not
                // if not then push it into the Queue
                if (!inQueue[v]) 
                {
                    q.add(v);
                    inQueue[v] = true;
                }
            }
        }
    }
  
    // Print the result
    print_distance(d, V);
}
  
// Driver code
public static void main(String[] args)
{
    int V = 5;
    int S = 1;
    for (int i = 0; i < graph.length; i++)
    {
        graph[i] = new Vector();
    }
      
    // Connect vertex a to b with weight w
    // addEdge(a, b, w)
    addEdge(1, 2, 1);
    addEdge(2, 3, 7);
    addEdge(2, 4, -2);
    addEdge(1, 3, 8);
    addEdge(1, 4, 9);
    addEdge(3, 4, 3);
    addEdge(2, 5, 3);
    addEdge(4, 5, -3);
  
    // Calling shortestPathFaster function
    shortestPathFaster(S, V);
}
}
  
// This code is contributed by 29AjayKumar


C#
// C# implementation of SPFA
using System;
using System.Collections.Generic;
  
class GFG
{
    class pair
    { 
        public int first, second; 
        public pair(int first, int second) 
        { 
            this.first = first; 
            this.second = second; 
        } 
    }
       
// Graph is stored as vector of vector of pairs
// first element of pair store vertex
// second element of pair store weight
static List []graph = new List[100000];
   
// Function to add edges in the graph
// connecting a pair of vertex(frm) and weight
// to another vertex(to) in graph
static void addEdge(int frm, int to, int weight)
{
   
    graph[frm].Add(new pair( to, weight ));
}
   
// Function to print shortest distance from source
static void print_distance(int []d, int V)
{
    Console.Write("Vertex \t\t Distance"
        + " from source" +"\n");
   
    for (int i = 1; i <= V; i++) 
    {
        Console.Write("{0} \t\t {1}\n", i, d[i]);
    }
}
   
// Function to compute the SPF algorithm
static void shortestPathFaster(int S, int V)
{
    // Create array d to store shortest distance
    int []d = new int[V + 1];
   
    // Boolean array to check if vertex
    // is present in queue or not
    bool []inQueue = new bool[V + 1];
   
    // Initialize the distance from source to
    // other vertex as int.MaxValue(infinite)
    for (int i = 0; i <= V; i++) 
    {
        d[i] = int.MaxValue;
    }
    d[S] = 0;
   
    Queue q = new Queue();
    q.Enqueue(S);
    inQueue[S] = true;
   
    while (q.Count!=0)
    {
   
        // Take the front vertex from Queue
        int u = q.Peek();
        q.Dequeue();
        inQueue[u] = false;
   
        // Relaxing all the adjacent edges of
        // vertex taken from the Queue
        for (int i = 0; i < graph[u].Count; i++)
        {
   
            int v = graph[u][i].first;
            int weight = graph[u][i].second;
   
            if (d[v] > d[u] + weight) 
            {
                d[v] = d[u] + weight;
   
                // Check if vertex v is in Queue or not
                // if not then push it into the Queue
                if (!inQueue[v]) 
                {
                    q.Enqueue(v);
                    inQueue[v] = true;
                }
            }
        }
    }
   
    // Print the result
    print_distance(d, V);
}
   
// Driver code
public static void Main(String[] args)
{
    int V = 5;
    int S = 1;
    for (int i = 0; i < graph.Length; i++)
    {
        graph[i] = new List();
    }
       
    // Connect vertex a to b with weight w
    // addEdge(a, b, w)
    addEdge(1, 2, 1);
    addEdge(2, 3, 7);
    addEdge(2, 4, -2);
    addEdge(1, 3, 8);
    addEdge(1, 4, 9);
    addEdge(3, 4, 3);
    addEdge(2, 5, 3);
    addEdge(4, 5, -3);
   
    // Calling shortestPathFaster function
    shortestPathFaster(S, V);
}
}
  
// This code is contributed by PrinciRaj1992


Python3
# Python3 implementation of SPFA
from collections import deque
   
# Graph is stored as vector of vector of pairs
# first element of pair store vertex
# second element of pair store weight
graph = [[] for _ in range(100000)]
  
# Function to add edges in the graph
# connecting a pair of vertex(frm) and weight
# to another vertex(to) in graph
def addEdge(frm, to, weight):
  
    graph[frm].append([to, weight])
  
# Function to prshortest distance from source
def print_distance(d, V):
    print("Vertex","\t","Distance from source")
  
    for i in range(1, V + 1):
        print(i,"\t",d[i])
  
# Function to compute the SPF algorithm
def shortestPathFaster(S, V):
  
    # Create array d to store shortest distance
    d = [10**9]*(V + 1)
  
    # Boolean array to check if vertex
    # is present in queue or not
    inQueue = [False]*(V + 1)
  
    d[S] = 0
  
    q = deque()
    q.append(S)
    inQueue[S] = True
  
    while (len(q) > 0):
  
        # Take the front vertex from Queue
        u = q.popleft()
        inQueue[u] = False
  
        # Relaxing all the adjacent edges of
        # vertex taken from the Queue
        for i in range(len(graph[u])):
  
            v = graph[u][i][0]
            weight = graph[u][i][1]
  
            if (d[v] > d[u] + weight):
                d[v] = d[u] + weight
  
                # Check if vertex v is in Queue or not
                # if not then append it into the Queue
                if (inQueue[v] == False):
                    q.append(v)
                    inQueue[v] = True
  
    # Print the result
    print_distance(d, V)
  
# Driver code
if __name__ == '__main__':
    V = 5
    S = 1
  
    # Connect vertex a to b with weight w
    # addEdge(a, b, w)
  
    addEdge(1, 2, 1)
    addEdge(2, 3, 7)
    addEdge(2, 4, -2)
    addEdge(1, 3, 8)
    addEdge(1, 4, 9)
    addEdge(3, 4, 3)
    addEdge(2, 5, 3)
    addEdge(4, 5, -3)
  
    # Calling shortestPathFaster function
    shortestPathFaster(S, V)
  
# This code is contributed by mohit kumar 29


输出:
Vertex    Distance from source
1          0
2          1
3          8
4          -1
5          -4

时间复杂度:
平均时间复杂度: O(| E |)
最坏情况下的时间复杂度:O(| V |。| E |)
注意:还没有证明平均运行时间会受到限制。

参考:最短路径更快算法