以下算法的输入:点的规模n,边的规模m
单源最短路
- Dijkstra算法
- 求一个点到其他点的最短路;权值必须为正
- 时间复杂度O(n2)
#Dijkstra伪代码
输入:带权有向图G=<V,E,W>,源点s∈V
输出:数组L,对所有j∈V-{s},L[j]表示s到j的最短路径上j前一个结点的标号
1. S←{s}
2. dist[s]←0
3. for i∈V-{s} do
4. dist[i]←w(s,i) //如果s到i没有边,w(s,i)=∞
5. while V-S≠∅ do
6. 从V-S中取出具有相对S的最短路径的结点j,k是路径上连接j的结点
7. S←S∪{j};L[j]←k
8. for i∈V-S do
9. if dist[j]+w[j,i]<dist[j]
10. then dist[j]=dist[j]+w[j,i]
- Bellman-Ford算法(不常用)
- 求一个点到其他点的最短路;权值可正可负
- 时间复杂度O(mn)(稀疏图m=θ(n),时间复杂度O(n2);稠密图m=θ(n2),时间复杂度O(n3)
#Bellman-Ford伪代码;摘自维基百科
function BellmanFord(list vertices, list edges, vertex source) is
// This implementation takes in a graph, represented as
// lists of vertices (represented as integers [0..n-1]) and edges,
// and fills two arrays (distance and predecessor) holding
// the shortest path from the source to each vertex
distance := list of size n
predecessor := list of size n
// Step 1: initialize graph
for each vertex v in vertices do
distance[v] := inf // Initialize the distance to all vertices to infinity
predecessor[v] := null // And having a null predecessor
distance[source] := 0 // The distance from the source to itself is, of course, zero
// Step 2: relax edges repeatedly
repeat |V|−1 times:
for each edge (u, v) with weight w in edges do
if distance[u] + w < distance[v] then
distance[v] := distance[u] + w
predecessor[v] := u
// Step 3: check for negative-weight cycles
for each edge (u, v) with weight w in edges do
if distance[u] + w < distance[v] then
error "Graph contains a negative-weight cycle"
return distance, predecessor
- Floyd算法
- 求每个点到其他点的最短路
- 时间复杂度O(n3)
#Floyd伪代码
#d(i,j)表示点i到点j的最短距离,h(i,j)表示路径上经过的结点
1.for i=1 to n do
2. for j=1 to n do
3. if i=j then d(i,i)←0,h(i,i)←i
4. else if <i,j>∈E then d(i,j)←w(i,j),h(i,j)←j
5. else d(i,j)←+∞,h(i,j)←0
6. for k=1 to n do
7. for i=1 to n ∧ i≠k do
8. for j=1 to n ∧ j≠k do
9. if d(i,j)>d(i,k)+d(k,j) then
10. d(i,j)←d(i,k)+d(k,j) then
11. d(i,j)←d(i,k)+d(k,j),h(i,j)←h(i,k)
12. if d(i,i)<0 then return "存在负回路",d,h
13. return d,h
最小生成树
- Prim算法
- 稠密图算法效率较高
- 时间复杂度O(n2)
#Prim伪代码
输入:连通图G=<V,E,W>
输出:G的最小生成树T
1.S←{1};T=∅
2.while V-S≠∅ do
3. 从V-S中选择j使得j到S中顶点的边e的权最小;T←T∪{e}
4. S←S∪{j}
- Kruskal算法
- 稀疏图算法效率较高
- 时间复杂度O(mlogn)(稀疏图m=θ(n),时间复杂度
O(nlogn);稠密图m=θ(n2),时间复杂度O(n2logn)
#Kruskal伪代码
输入:连通图G<V,E,W>
输出:G的最小生成树
1.按照权从小到大顺序排序G中的边,使得E={e1,e2,...,em}
2.T←∅
3.repeat
4. e←E中的最短边
5. if e的两端点不在同一个连通分支
6. then T←T∪{e} //把e加入树中,合并连通分支
7. E←E-{e}
8. until T包含了n-1条边