8.10 睡觉集合与钉耙编程
有时候我们不需要太复杂的结论与算法,只要时间复杂度够就行了。
交朋友
给定 \(n\) 个点和 \(m\) 条有向边。每次可以执行操作:找到 \((p,u)\in E\) 与 \((p,v)\in E\),连 \((u,v)\) 和 \((v,u)\)。问图中最大能有多少条边
后来连的有三种边:
- 两条 \(m\) 里的边连起来的。
- 一条 \(m\) 里的边加一条新增的边
- 两条新增的边
第一种好算。考虑与点 \(u\) 相连的点集 \(V\),\(V\) 中点最终必定两两联通,所以可以把它们用并查集缩成一个点。
之后我们把所有缩过的点放在一起 \(bfs\),当发现点集 \(V\) 有连向 \(p\) 的出边,则将 \(p\) 及其所属集合加入点集 \(V\)。因为此时 \(p\) 对集合 \(V\) 中的每个点都满足操作条件。
知道的点集以后,算边数是简单的。要注意原有的有向边不能重复算。