0x60图论 做题记录
如有任何问题,请务必在页面底部评论
0x62 最小生成树
AcWing 346. 走廊泼水节
给定一棵 \(N\) 个节点的树,要求增加若干条边,把这棵树扩充为完全图,并满足图的唯一最小生成树仍然是这棵树。求增加的边的权值总和最小是多少。\(N \le 6000\),边权均为非负整数。
考虑加入任意一条边,均会在树上构成一个环,而我们要保证新加入的边边权在这个环上是严格最大的,否则删去权值相等或更大的边,得到的生成树权值更小,不合题意。根据这个思路,我们可以枚举树上一对点,暴力找到它们在树上的路径,并将这条边的权值设为 \(w_{max} + 1\)。这样复杂度是 \(O(n^3)\) 的。
也可以倒着来,考虑贡献,当一条边的权值为 \(w\),有多少边的权值为 \(w + 1\)?为了使每条边的权值都达到下界,我们可以使用一个倒着的 Kruskal 来模拟。从最小的边开始,设当前边为 \((x, y, z)\),连接两个连通块 \(S_x, S_y\),对于每个连通块内部的边,由于我们从小到大枚举,权值一定 \(\le z\),对于 \(\forall u \in S_x, \forall v \in S_y\),若 \((u, v) \neq (x, y)\),由于是完全图,则 \((u, v)\) 之间必有一条连边,而这条连边的权值即为 \(w_{x, y} + 1\)。累加 \((|S_x| \times |S_y| - 1) \times (w_{x, y} + 1)\) 到答案中即可。代码。
AcWing 347. 野餐规划
给定一张 \(N\) 个点,\(M\) 条边的无向图,求出无向图的一棵最小生成树,满足 \(1\) 号节点的度数不超过给定的整数 \(S\)。\(N \le 30\)。
- 解法一:删边(\(O(n^4)\))
先忽略度数限制,求出一棵最小生成树。如果 \(1\) 号节点度数 \(\le S\),那么这就是最优选择。如果 \(> S\),则肯定需要断某些边;当一条边断掉之后,会多出来一个连通块,然后我们在这两个连通块之间找一条最短的边(除了断掉的那条)连上,将答案加上这次操作的差值,这样一定是最优的。 - 解法二:加边(\(O(n^2)\))
首先标记出删掉 \(1\) 号节点后剩下的若干连通块,当连通块个数 \(> S\) 时,本题无解。求每个连通块的最小生成树,之后每个连通块向 \(1\) 号节点连一条尽量小的边,得到一棵生成树,现在 \(1\) 号节点的度数为 \(T\),我们还可以改动剩下的 \(S - T\) 条边,使答案更优。
考虑每条从 \(1\) 出发且当前不在生成树中的边 \((1, y, z)\)。找到 \(y\) 在生成树上到 \(1\) 的路径中最大的边 \((u, v, w)\)。在所有这些边中求出使得 \(w - z\) 最大的点 \(y_0\)。删掉 \((u_0, v_0)\),加入 \((1, y_0)\),答案就会变小 \(w_0 - z_0\)。
重复 \(S - T\) 次,或者直到 \(w_0 - z_0 \le 0\),就得到的题目所求生成树。
代码,实现有些细节。
AcWing 348. 最优比率生成树
给定一张 \(N\) 个点、\(M\) 条边的无向图(\(1 \le N, M \le 10000\)),图中每条边 \(e\) 都有一个收益 \(C_e\) 和一个成本 \(R_e\)。求该图的一棵生成树 \(T\),使树中各边的收益之和除以成本之和,即 \(\dfrac{\sum_{e \in T} C_e }{\sum_{e \in T} R_e}\) 最大。
题目求一分式的值最大,用 0/1 分数规划转化为二分来解决。对于整个边集 \(E = \{e_1, e_2, \cdots\}\),第 \(i\) 条边有两个权值 \(C_i\) 和 \(R_i\),同时我们设一组 0/1 变量 \(x_i\),表示第 \(i\) 条边是否选择,即求 \(\dfrac{\sum x_i C_i}{\sum x_i R_i}\) 最大。设当前二分到的值为 \(mid\),答案为 \(ans\)。
我们以 \(mid \le ans\) 的情况为例,则必存在一组 \(x\),满足:
由于存在,我们只需使 \(\min\{\sum x_i (mid R_i - C_i)\} \le 0\)。当 \(mid > ans\) 同理,只是变为对于任意一组 \(x\),都有 \(\sum x_i (mid R_i - C_i) > 0\),即 \(min\{\sum x_i (mid R_i - C_i)\} > 0\)。
这样,我们就可以通过后面这个式子与 \(0\) 的大小得知当前答案是否合适,通过二分将求一个分式的值转化为简单的大小判断。注意到,此时小括号中的值可看做常量,只有 \(x\) 是不知道的,由于只关心其最小值,这就相当于将原图每条边的权值调整为 \(mid R_i - C_i\),再求出其最小生成树,Prim 即可。代码。
AcWing 349. 黑暗城堡
一张 \(n\) 个点,\(m\) 条边的无向图,求其最短路树的数量。\(N \le 1000\)。
一道与以前的知识联系起来的题。最短路树不再赘述,也是图的一种生成树。我们可以先使用 Dijkstra 算法求出从 \(1\) 出发到达每个房间的最短路长度,记为 \(D_i\)。然后将每个节点根据 \(D_i\) 的值排序,从小到大依次考虑把每个节点 \(p\) 加入最短路树有多少种方法。与 Prim 算法类似,我们总是维护当前“最短路径生成树”的一部分,记为 \(T\)。统计有多少 \(\forall u \in T, D_p = D_u + w_{u, p}\)(加法原理),最后把每一步统计的数量乘起来(乘法原理),就得到了最后的答案。代码。
扩展:最小树形图与朱-刘算法

AcWing和一些其他题目的简要思路,都是好题,不记就忘了
浙公网安备 33010602011771号