给定一个有权有向图 \(G=\langle V,A\rangle,w:A\mapsto\mathbb{R}\) 和一个根 \(r\in G\),求以 \(r\) 为根的最小生成树,满足每条边都是父亲指向儿子(外向树)。
暴力做法
不失一般性,我们可以简单的 \(O(|V|+|A|)\) \(\text{dfs}\) 判断这样的树是否存在,并且对于平行弧,我们可以只保留较小的那条。
然后我们约定 \(E\subseteq A,w(E)=\sum\limits_{e\in E}w(e)\)。
用 \(\pi(v)\) 表示所有指向 \(v\) 的弧 \(e=(u,v)\) 中 \(w(e)\) 最小的 \(u\)。考虑 \(M=\langle V,\{(\pi(v),v):\forall v\in V\setminus\{r\}\}\rangle\),如果 \(M\) 中无环,那么 \(M\) 就是所求。
若 \(M\) 中有环,我们考虑递归地缩点:
任选一个环 \(C\in M\)。新建节点 \(v_C\),建立新图 \(G^\prime=\langle V^\prime,A^\prime\rangle,w^\prime:A^\prime\mapsto\mathbb{R}\),其中 \(V^\prime=(V\setminus C)\cup\{v_C\}\)。
\(A^\prime\) 满足,\(\forall e=(u,v)\in A\land e\not\in C\):
- \(u,v\not\in C\),\(e=(u,v)\in A^\prime,w^\prime(e)=w(e)\);
- \(u\in C,v\not\in C\),\(e^\prime=(v_C,v)\in A^\prime,p=(\pi(u),u),w^\prime(e^\prime)=w(e)-w(p)\);
- \(u\not\in C,v\in C\),\(e=(u,v)\in A^\prime,w^\prime(e)=w(e)\)。
用 \(f(G,r)\) 表示图 \(G\) 中以 \(r\) 为根的最小树形图大小,有 \(f(G,r)=f(G^\prime,r)+w(C)\)。
没有环的情况,正确性是显然的。
有环的时候,我们其实应该选择一条进入环的边,但是我们不知道具体选择哪一条,但是因为是有向边,所以从 \((u,v)\) 进入环之后,\((\pi(v),v)\) 这条边就没必要选了。不难发现我们恰好需要一条边来打破一个环,于是就按照上述方法得到 \(w^\prime\) 即可保证贪心的正确性。
按照刚刚讲的思路暴力,每轮建立 \(M\) 的代价是 \(O(|V|+|A|)\),找环的代价也是 \(O(|V|+|A|)\),然后每次缩点至少减少 \(1\) 个点,至多执行 \(O(|V|)\) 轮。于是整体复杂度就是 \(O(|V|^2+|V||A|)\),注意到不连通可以 \(O(|V|+|A|)\) 判定,于是可以写成 \(O(|V||A|)\)(忽略没有弧的情况)。
我们发现每轮全部重新计算太浪费了,只需要修改环上的点。于是我们用可并堆维护每个点的入边(如果要做到理论最优,需要 \(\text{fib}\) 堆),再用并查集维护缩点的关系,这样就可以做到 \(O(|A|+|V|\log|V|)\) 了。
代码?鸽子能更新就不错了。