Complete the MST 题解
一、前言
截至目前,这是练习的第一道完全没有听别人提示的题。hh
二、题解
Hint 1:
首先没有确定边权的边,边权分配一定是一条边的权值为
r
e
t
=
v
a
l
1
⨁
v
a
l
2
.
.
.
⨁
v
a
l
m
ret = val_1 \bigoplus val_2 ... \bigoplus val_m
ret=val1⨁val2...⨁valm,其余边的边权为 0。
因为这样分配只有未确定边全选的情况才会贡献 ret,而其他分配方式除此情况提供 ret 的贡献,还一定会在一些选择方式中提供贡献,所以这样的分配方式可以以不变应万变。
Hint 2:
如果没有确定边权的边的数量 (number_uncertain) 大于了 n - 1,那么最小生成树中没有确定边权的边的权值一定为 0。
因为生成树的边数为 n - 1,一定有一个没有确定边权的边没有用到,让他的权值为 ret 就行了。
Hint 3:
根据 Kruskal 算法,我们会从边权小的边开始考虑选择,所以我们可以先连边权为 0 的边。
根据上面的三个 Hint,我们可以有如下的解法。
情况1 : n u m b e r _ u n c e r t a i n > n − 1 number\_uncertain > n - 1 number_uncertain>n−1
用 Boruvka 算法。
s[u] 记录以 u 为根的并查集的不能相连的点的编号。
并查集合并时用按秩合并,在较小的并查集里删除不存在于大并查集里的元素。
连通块向外连边时,对于该连通块打一个不可选的编号的表,随便选择一个可选的点,可以考虑每个不可选的编号的相邻编号(因为这种选法和全部遍历选择的存在性是等价的)。
时间复杂度均摊下来是
O
(
l
o
g
2
V
(
V
+
E
)
)
O (log_2V (V + E))
O(log2V(V+E))。
这样我们将所有的边权为零的边连好了,然后在连好的图上跑一个 Kruskal 就行了。
情况2 : n u m b e r _ u n c e r t a i n ≤ n − 1 number\_uncertain \leq n - 1 number_uncertain≤n−1
这时点的个数不超过
1000
1000
1000 (上界但不是上确界),可以将未确定的边的边权设为 0 跑一个 kruskal,如果未确定的边全部属于 MST 中,那么枚举任意两个点,连接后在形成的环上去掉一个边权为 0 的边(如果没有边权为 0 的边则不能有这样的生成树)。
注意 1: 不要忘了让一个未确定边的边权为 ret 的生成树
注意 2: 实际计算时并不需要连接删边的操作,这样的描述仅便于理解。