先决条件: Bellman-Ford 算法
给定一个有V个顶点、 E 个边和一个源顶点S 的有向加权图。任务是在给定图中找到从源顶点到所有其他顶点的最短路径。
例子:
Input: V = 5, S = 1, arr = {{1, 2, 1}, {2, 3, 7}, {2, 4, -2}, {1, 3, 8}, {1, 4, 9}, {3, 4, 3}, {2, 5, 3}, {4, 5, -3}}
Output:
1, 0
2, 1
3, 8
4, -1
5, -4
Explanation: For the given input, the shortest path from 1 to 1 is 0, 1 to 2 is 1 and so on.
Input: V = 5, S = 1, arr = {{1, 2, -1}, {1, 3, 4}, {2, 3, 3}, {2, 4, 2}, {2, 5, 2}, {4, 3, 5}, {4, 2, 1}, {5, 4, 3}}
Output:
1, 0
2, -1
3, 2
4, 1
5, 1
方法:最短路径更快算法基于 Bellman-Ford 算法,其中每个顶点都用于松弛其相邻顶点,但在 SPF 算法中,会维护一个顶点队列,并且仅当该顶点松弛时才将顶点添加到队列中。这个过程重复,直到没有更多的顶点可以放松。
可以执行以下步骤来计算结果:
- 创建一个数组d[]来存储所有顶点到源顶点的最短距离。除了 d[S] = 0 之外,用无穷大初始化这个数组,其中S是源顶点。
- 创建一个队列Q并将起始源顶点推入其中。
- 当队列不为空时,对图中的每条边(u,v)执行以下操作
- 如果 d[v] > d[u] + edge(u, v) 的权重
- d[v] = d[u] + 边的权重(u, v)
- 如果顶点 v 不存在于队列中,则将顶点 v 推入队列。
- 当队列不为空时,对图中的每条边(u,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
Javascript
Vertex Distance from source
1 0
2 1
3 8
4 -1
5 -4
时间复杂度:
平均时间复杂度: O(|E|)
最坏时间复杂度:O(|V|.|E|)
注意:平均运行时间的限制尚未得到证明。
参考资料:最短路径更快算法
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。