我将描述该问题的多对数解决方案。让我们介绍一些定义。我们将表示:
- 图的顶点集
V
,图的边集E
和 MST 边集T
.
- 顶点之间的图的边
v
and u
by {v, u}
.
- 边重
e
by W(e)
和 MST 的权重W(T)
.
我们来考虑一下功能MaxEdge(v, u)
,它等于之间的简单路径上具有最大权重的边v
and u
属于T
。如果有几条权重最大的边MaxEdge(v, u)
可以等于它们中的任何一个。
为了找到第二好的MST,我们需要找到这样的边缘x = {p, q}
, that:
-
x
不属于T
.
- 功能
W(x) - W(MaxEdge(p, q))
是最小的可能。
可以证明第二好的 MST 可以通过删除来构造MaxEdge(p, q)
from T
然后添加x = {p, q}
to T
.
现在让我们构建一个能够计算的数据结构MaxEdge(p, q)
in O(log|V|)
.
让我们为树挑选一个根T
(它可以是任何顶点)。我们将调用顶点之间的简单路径中的边数v
根 - 顶点的深度v
,并表示它Depth(v)
。我们可以计算Depth(v)
对于所有顶点O(|V|)
by 深度优先搜索 https://en.wikipedia.org/wiki/Depth-first_search.
让我们计算两个函数,这将帮助我们计算MaxEdge(p, q)
:
-
Parent(v, i)
,它等于作为顶点的父级(可能是非直接父级)的顶点v
深度等于Depth(v) - 2^i
.
-
MaxParentEdge(v, i)
,等于MaxEdge(v, Parent(v, i))
.
它们都可以通过递归函数来计算,并记忆在O(|V|log|V|)
.
// Assumes that 2^i <= Depth(v)
Vertex Parent(Vertex v, Vertex i) {
if (i == 0) return direct_parent[v];
if (Memorized(v, i)) return memorized_parent[v][i];
memorized_parent[v][i] = Parent(Parent(v, i - 1), i - 1);
return memorized_parent[v][i];
}
Edge MaxParentEdge(Vertex v, Vertex i) {
if (i == 0) return Edge(v, direct_parent[v]);
if (Memorized(v, i)) return memorized_parent_edge[v][i];
Edge e1 = MaxParentEdge(v, i - 1);
Edge e2 = MaxParentEdge(Parent(v, i - 1), i - 1);
if (W(e1) > W(e2)) {
memorized_parent_edge[v][i] = e1;
} else {
memorized_parent_edge[v][i] = e2;
}
return memorized_parent_edge[v][i];
}
在我们准备好计算之前MaxEdge(p, q)
,让我们介绍一下最终的定义。Lca(v, u)
将表示最低共同祖先 https://en.wikipedia.org/wiki/Lowest_common_ancestor顶点数v
and u
在有根的树上T
。有许多众所周知的数据结构可以进行计算Lca(v, u)
查询于O(log|V|)
甚至在O(1)
(您可以在以下位置找到文章列表维基百科 https://en.wikipedia.org/wiki/Lowest_common_ancestor).
计算MaxEdge(p, q)
我们将在之间划分路径p
and q
分为两部分:从p
to Lca(p, q)
, from Lca(p, q)
to q
。这些部分中的每一个看起来都像是从顶点到其某些父级的路径,因此我们可以使用我们的Parent(v, i)
and MaxParentEdge(v, i)
计算函数MaxEdge
对于这些部分。
Edge MaxEdge(Vertex p, Vertex q) {
Vertex mid = Lca(p, q);
if (p == mid || q == mid) {
if (q == mid) return QuickMaxEdge(p, mid);
return QuickMaxEdge(q, mid);
}
// p != mid and q != mid
Edge e1 = QuickMaxEdge(p, mid);
Edge e2 = QuickMaxEdge(q, mid);
if (W(e1) > W(e2)) return e1;
return e2;
}
Edge QuickMaxEdge(Vertex v, Vertex parent_v) {
Edge maxe = direct_parent[v];
string binary = BinaryRepresentation(Depth(v) - Depth(parent_v));
for (int i = 0; i < binary.size(); ++i) {
if (binary[i] == '1') {
Edge e = MaxParentEdge(v, i);
if (W(e) > W(maxe)) maxe = e;
v = Parent(v, i);
}
}
return maxe;
}
基本功能QuickMaxEdge(v, parent_v)
跳跃长度2^i
覆盖之间的距离parent_v
and v
。在跳跃过程中,它使用预先计算的值MaxParentEdge(v, i)
更新答案。
考虑到MaxParentEdge(v, i)
and Parent(v, i)
是预先计算的,MaxEdge(p, q)
工作于O(log|V|)
,这导致我们O(|E|log|V|)
解决最初的问题。我们只需要迭代所有不属于的边T
并计算W(e) - MaxEdge(p, q)
对于他们每个人来说。