23.2-1对于同一个输人图,Kruskal 算法返回的最小生成树可以不同。这种不同来源于对边进行排序时,对权重相同的边进行的不同处理。证明:对于图G的每棵最小生成树T,都存在一种办法来对G的边进行排序,使得Kruskal算法所返回的最小生成树就是T。
假设我们想选择 T 作为最小生成树。然后,为了使用 Kruskal 算法获得此树,我们将首先按边的权重对边进行排序,然后通过选取包含在最小生成树中的一条边来解决边权重中的连接,并将所有不在T中的边权视为稍大,即使它们具有相同的实际权重。 通过这种排序,我们能够找到与所有最小生成树w(T)具有相同权重的树。但是,由于我们优先考虑在T中的边,因此我们将选择T中的边,而不是其他最小生成树中可能存在的任何其他边。
书上的kruskal:
23.2-2假定 我们用邻接矩阵来表示图G=(V, E)。请给出Prim算法的一种简单实现,使其运行时间为O(V2)。
在算法的每一步,我们将从到目前为止创建的树中的顶点添加一个边到不在树中的顶点,这样这条边的权重最小。因此,对于不在树中的每个顶点,知道从该顶点到树中某个权重最小的顶点的边将是有用的。我们将这些信息存储在数组 A 中,其中 A[u] = (v, w) , w 是 (u, v) 的权重,并且在从 u 到目前为止构建的树中的某个顶点 v 的边权重中最小。我们将使用 A[u].1 访问 v,使用 A[u].2 访问 w。
PRIM-ADJ(G, w, r)
#r为起点,G为图,w(r,i)为r到i的权值
initialize A with every entry = (NIL, ∞)
T = {r}
for i = 1 to V
if Adj[r, i] != 0 #不为0说明r到i有边
A[i] = (r, w(r, i))
for each u in V - T#prim每次选择一个不在当前生成树中的最小权边加入树
k = min(A[i].2)#连接k和树中结点所有边中最小边的权重
T = T ∪ {k}
k.π = A[k].1#k在树T中的父结点
for i = 1 to V
if Adj[k, i] != 0 and Adj[k, i] < A[i].2
A[i] = (k, Adj[k, i])
书上的prim:
23.2-3对于稀疏图G=(V, E),这里|E| =Θ(V),使用斐波那契堆实现的Prim算法是否比使用二叉堆实现的算法更快?对于稠密图又如何呢?| E|和 |V|必须具备何种关系才能使斐波那契堆的实现在渐近级别上比二叉堆的实现更快?
用二进制堆实现的 Prim 算法的运行时为
O
(
(
V
+
E
)
lg
(
V
)
)
O((V + E) \lg(V))
O((V+E)lg(V)),在稀疏情况下,它只是
O
(
V
lg
(
V
)
)
O(V \lg(V))
O(Vlg(V))。
斐波那契堆的实现是
O
(
E
+
V
lg
(
V
)
)
O(E + V \lg(V))
O(E+Vlg(V)) =
O
(
V
+
V
lg
(
V
)
)
O(V + V \lg(V))
O(V+Vlg(V)) =
O
(
V
lg
(
V
)
)
O(V \lg(V))
O(Vlg(V))。
因此,在稀疏图情况下,这两种算法具有相同的渐近运行时。
在稠密图的情况下,我们有二进制堆实现的运行时
O
(
(
V
+
E
)
lg
(
V
)
)
O((V + E) \lg(V))
O((V+E)lg(V)) =
O
(
(
V
+
V
2
)
lg
(
V
)
)
O((V + V 2 ) \lg(V))
O((V+V2)lg(V)) =
O
(
V
2
lg
(
V
)
)
O(V^2 \lg(V))
O(V2lg(V))。
然而,斐波那契堆实现的运行时为
O
(
E
+
V
lg
(
V
)
)
O(E +V \lg(V))
O(E+Vlg(V)) =
O
(
V
2
+
V
lg
(
V
)
)
O(V 2 +V \lg(V))
O(V2+Vlg(V)) =
O
(
V
2
)
O(V^2 )
O(V2)。
因此,在稠密图的情况下,我们发现斐波那契堆实现渐近更快。
只要
E
=
ω
(
V
)
E = ω(V)
E=ω(V),斐波那契堆实现就会渐近更快。假设我们有一些比线性增长更快的函数,比如
f
,
E
=
f
(
V
)
f,E = f(V)
f,E=f(V)。
二进制堆实现将具有运行时
O
(
(
V
+
E
)
lg
(
V
)
)
O((V + E) \lg(V))
O((V+E)lg(V)) =
O
(
(
V
+
f
(
V
)
)
lg
(
V
)
)
O((V + f(V))\lg(V))
O((V+f(V))lg(V)) =
O
(
f
(
V
)
lg
(
V
)
)
O(f(V ) \lg(V))
O(f(V)lg(V))。
但是,我们有斐波那契堆实现的运行时将具有运行时
O
(
E
+
V
lg
(
V
)
)
O(E + V \lg(V))
O(E+Vlg(V)) =
O
(
f
(
V
)
+
V
lg
(
V
)
)
O(f(V ) + V \lg(V))
O(f(V)+Vlg(V))。
这个运行时间是
O
(
f
(
V
)
)
O(f(V))
O(f(V))或
O
(
V
lg
(
V
)
)
O(V \lg(V))
O(Vlg(V)),这取决于
f
(
V
)
f(V)
f(V)的增长速度是否分别比
V
lg
(
V
)
V \lg(V)
Vlg(V)快或慢。
无论哪种情况,我们的运行时间都比
O
(
f
(
V
)
lg
(
V
)
)
O(f(V )\lg(V))
O(f(V)lg(V))快。
23.2-4假定图中 的边权重全部为整数,且在范围1~|V|内。在此种情况下,Kruskal 算法最快能多快?如果边的权重取值范围在1到某个常数W之间呢?
如果边权重是 1 到 |V | 范围内的整数,我们可以通过使用计数排序在线性时间内按权重对边进行排序,使 Kruskal 算法在 O ( E α ( V ) ) O(E_α(V)) O(Eα(V)) 时间内运行。如果边权重是由常量限定的整数,采取相同的方法,因为运行时由决定边是否加入不相交森林的任务主导,这与边权重无关。
23.2-5假定图 中边的权重取值全部为整数,且在范围1~|V|内。Prim 算法最快能多快?如果边的权重取值范围在1到某个常数W之间呢?
如果边权重都在 1、. . . 、|V |,那么,我们可以想象将边添加到列表数组中,其中权重 i 的边进入数组索引 i 中的列表。然后,要减少一个元素,我们只需将其从当前包含它的列表中(常量时间)中删除,并将其添加到与其新值(也是常量时间)对应的列表中。为了提取最小的边缘,我们在包含非空列表的所有索引中维护一个链表,也可以只用恒定的额外工作来维护。由于所有这些操作都可以在恒定时间内完成,因此我们有一个总运行时间
O
(
E
+
V
)
O(E+V)
O(E+V)。 如果边权重都位于某个有界范围中,假设在 1 到 W 的范围内。然后,我们可以只在第 20 章中给出的 vEB 树结构中在时间
O
(
l
g
(
l
g
(
l
g
(
W
)
)
)
O(lg(lg(lg(W)))
O(lg(lg(lg(W)))中执行两个必需的操作,这意味着总运行时间可以设为
O
(
(
V
+
E
)
l
g
(
l
g
(
W
)
)
)
O((V + E) lg(lg(W)))
O((V+E)lg(lg(W)))。
23.2-6 假定一个图中所有的边权重均匀分布在半开区间[0,1)内。Prim算法和Kruskal算法哪一个可以运行得更快?
对于从均匀分布中提取的输入,使用带有 Kruskal 算法的桶排序,用于按权重对边进行预期的线性时间排序。这将实现预期的运行时
O
(
E
α
(
V
)
)
O(E_\alpha(V))
O(Eα(V))
由于Prim算法时间主要耗费在维护优先级队列的性质上,加速的方法是使用更加复杂的数据结构,比如基数堆,斐波那契堆。
23.2-7 假定图G的一棵最小生成树已经被计算出来。如果在图中加入一个新结点及其相关的新边,我们需要多少时间来对最小生成树进行更新?
我们首先将所有边添加到新顶点。然后,我们预制一个根植于该顶点的DFS。当我们向下时,我们会跟踪自DFS中每个顶点以来迄今为止看到的最大权重边缘。我们从练习 23.3-6 中知道,在有向图中,我们不需要考虑交叉边缘或前向边缘。然后,我们检测到的每个循环都将由后边缘形成。因此,我们只是删除自我们处于后边缘将要到达的顶点以来看到的最大重量的边缘。然后,我们将继续前进,直到我们删除的顶点比我们添加的许多边的度数少一个。这最终将是线性时间,因为我们可以重用在检测每个周期之前已经计算的部分 DFS。
23.2-8 Borden 教授提出了一个新的分治算法来计算最小生成树。该算法的原理如下:给定图G=(V, E),将V划分为两个集合V1和V2,使得|V1|和|V2|的差最多为1。设E1为端点全部在V1中的边的集合,E2为端点全部在V2中的边的集合。我们递归地解决两个子图G1=(V1,E1)和G2=(V2, E2)的最小生成树问题。最后,在边集合E中选择横跨切割V1和V2的最小权重的边来将求出的两棵最小生成树连接起来,从而形成一棵最后的最小生成树。
请证明该算法能正确计算出一棵最小生成树,或者举出反例来明说该算法不正确。
博登教授错了。考虑具有 4 个顶点的图形:a、b、c 和 d。设边分别为 (a, b)、(b、c)、(c、d)、(d、a),权重分别为 1、5、1 和 5。设 V1 = {a, d} 和 V2 = {b, c}。然后每个树上只有一个边缘入射,因此我们必须在 V1 和 V2 上采用的树精确地由边缘 (a, d) 和 (b, c) 组成,总权重为 10。加上连接它们的权重 1 边缘,我们得到权重 11。但是,MST 将使用两个权重 1 边和仅使用权重 5 边中的一个,总权重为 7。