学习笔记——图的算法

以下算法的输入:点的规模n,边的规模m

单源最短路

  1. 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]
  1. 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
  1. 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	

最小生成树

  1. 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}
  1. 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条边
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值