我将描述问题的多对数解法。我们来介绍一些定义。我们将表示:
- 集图的顶点由
V
,由E
设定图的边缘,并通过T
设置MST边。
- 顶点之间的图形的边缘
v
和u
由{v, u}
所示。
- 边缘的重量
e
由W(e)
和MST的重量为W(T)
。
让我们考虑功能MaxEdge(v, u)
,这等于与v
和u
之间的简单路径上的最大权重的边缘属于T
。如果有几个最大重量的边缘MaxEdge(v, u)
可以等于它们中的任何一个。
要找到第二个最好的MST,我们需要找到这样的边缘x = {p, q}
,即:
x
不属于T
。
- 功能
W(x) - W(MaxEdge(p, q))
是尽可能最小。
这是可能的,以证明所述第二最佳MST可以通过从T
除去MaxEdge(p, q)
,然后加入到x = {p, q}
T
来构造。
现在我们来构建一个数据结构,它将能够在O(log|V|)
中计算MaxEdge(p, q)
。
我们为树T
(它可以是任何顶点)选择一个根。我们将调用顶点v
与根之间的简单路径中的边数 - 顶点的深度v
,并将其表示为Depth(v)
。我们可以通过depth first search计算O(|V|)
中所有顶点的Depth(v)
。
让我们来计算两个功能,这将有助于我们计算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)
将表示根树T
中的顶点v
和u
的lowest common ancestor。有许多众所周知的数据结构允许在O(log|V|)
甚至O(1)
中计算Lca(v, u)
查询(您可以在Wikipedia找到文章列表)。
为了计算MaxEdge(p, q)
,我们将分p
和q
之间的路径分为两个部分:从p
到Lca(p, q)
,从Lca(p, q)
到q
。这些部分中的每一个看起来像从顶点到其父母的路径,因此我们可以使用我们的Parent(v, i)
和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
和v
之间的距离。在跳转期间,它使用预先计算的值MaxParentEdge(v, i)
来更新答案。
考虑到MaxParentEdge(v, i)
和Parent(v, i)
是预先计算的,MaxEdge(p, q)
作品O(log|V|)
,这使我们的O(|E|log|V|)
解决最初的问题。我们只需要遍历所有不属于T
的边,并为它们中的每一个计算W(e) - MaxEdge(p, q)
。
如果你可以添加一个psedocode,它会更合适,人们可以很容易地理解你的答案。 – arunmoezhi
请你详细说明为什么这个工程? – Math