1 条题解
-
0
1. 理解「完美点对」
题中定义:
对于两个地点 和 (),如果存在一种方式,从 走到 再回到 ,每条道路经过不超过一次,则 是完美点对。
注意:
图是无向连通图,可以有重边。
每条边最多走一次(在往返过程中)。
从 到 再回到 ,相当于在图上找一条从 到 的路径,然后再找一条从 到 的路径,且这两条路径边不相交(因为每条边最多一次)。
1.1 转化为图论概念
在无向图中,从 到 再回到 ,且边不重复,等价于 和 在同一个边双连通分量(Biconnected Component / 2-edge-connected component) 中。
理由:
在一个边双连通分量中,任意两点之间至少有两条边不相交的路径(Menger 定理)。 所以对于 和 在同一个边双内,我们可以用一条路径从 到 ,另一条不同的路径从 回到 ,且边不重复。
1.2 完美点对的数量计算
假设图由若干个边双连通分量 组成,每个边双的大小(顶点数)为 。
那么对于同一个边双 内的任意两个不同顶点 (),它们都是一个完美点对。 所以边双 贡献的完美点对数为:
不同边双之间的点对不是完美点对,因为从 到 必须经过割边,割边只能走一次,无法在往返中不重复使用。
因此总的完美点对数为:
$$K = \sum_{i=1}^m \binom{n_i}{2} = \sum_{i=1}^m \frac{n_i(n_i-1)}{2} $$
2. 问题转化
题目要求:给定 ,构造一个连通图,使得它的完美点对数为 ,并且 。
我们可以这样构造:
图由若干个边双组成,每个边双是一个完全图 (因为完全图是边双连通的,且能最大化该分量内的完美点对数)。
这些边双通过一些桥(割边)连接成连通图。
2.1 完全图的完美点对数
完全图 中任意两点之间都有 条边不相交的路径(其实任意两点间有 条边直接相连,但这里我们只关心它们是否在同一个边双内,显然 是边双连通的)。 贡献的完美点对数为:
2.2 构造方法
我们要用尽量少的顶点和边,构造出恰好 个完美点对。
思路:
把 拆成若干个 的和,每个 ,然后让这些完全图通过桥连接成连通图。
例如:
如果 ,可以取 ,因为 ,那么一个 就够了。 样例 2 给出的 个点的环 并不是 ,但 也是边双连通(没有割边),所以任意两点都是完美点对,也是 对。 所以不一定非要用完全图,只要该分量是边双连通,并且包含所有顶点对即可。
2.3 如何构造边双连通图且顶点数固定
对于 个顶点的边双连通图,最简单的是:
环 : 个顶点, 条边,任意两点间有两条边不相交路径(环的两方向),所以是边双连通。
完全图 : 条边,边数多但完美点对数最大。
为了节省边数,我们通常用环 来构造一个边双,它贡献的完美点对数也是 (因为任意两点都在同一个边双内)。
2.4 连接不同边双
假设我们有两个边双 和 ,它们之间用一条边(桥)连接,那么整个图是连通的,但 中的点与 中的点不在同一个边双内,所以它们之间不是完美点对。
因此总完美点对数就是:
$$K=\binom{n_1}{2}+\binom{n_2}{2}+···+\binom{n_m}{2} $$
3. 构造算法
我们要将 表示为:
并且总顶点数 ,总边数 (每个环 条边,加上 条桥)。
3.1 贪心分解
为了用最少的顶点数,我们尽量用大的 ,因为 增长快。
从最大的 开始,使得 ,然后 ,重复直到 。
3.2 例子
样例 1: 不够, 太大,所以只能 ,即两个 (即两个点连一条边)。 两个 就是两条边 和 ,然后需要连通它们:加一条桥 。 得到:
边双1:顶点 {1,2},边 (1,2)
边双2:顶点 {3,4},边 (3,4)
桥: (1,4) 总顶点数 4,总边数 5,与样例输出一致。
样例 2: ,所以一个环 即可。 输出 4 个顶点 4 条边:1-2, 2-3, 3-4, 4-1。
4. 一般构造步骤
初始化 ,列表 。
当 :
找最大的 使得 。
如果找不到 ,则取 ()。
。
将 加入 。
输出图:
总顶点数 。
每个分量 用一个环 构造(顶点连续分配)。
用额外的 条桥连接这些环(例如第一个环最后一个顶点连到下一个环第一个顶点)。
5. 顶点和边数上界
最坏情况 时,我们尽量用 大的环: ,所以 。 时,,一个环就够,,,满足 。
所以直接一个环 即可,其中 满足 如果 是三角数,否则需要调整。
5.1 如果不是三角数
如果 不是 ,我们分解成 ,直到 减到 0。
因为 ,总能分解。
6. 公式总结
完美点对数:
构造的图:
每个分量 顶点构成环 (边双连通)。
总顶点数 。
总边数 。
7. 示例构造代码(伪代码)
输入 K components = [] while K > 0: n = 2 while n*(n-1)//2 <= K: n += 1 n -= 1 # 此时 n 是最大的满足 C(n,2) <= K 的 if n < 2: n = 2 K -= n*(n-1)//2 components.append(n) # 构造图 分配顶点编号 输出 V = sum(components), E = sum(components) + len(components)-1 当前顶点 start = 1 for i, n in enumerate(components): # 输出环 for j in range(n): u = start + j v = start + (j+1)%n if j < n-1 or n == 2: # 避免 n=2 时输出两条相同边 输出边 (u, v) # 记录这个分量的最后一个顶点,用于桥接 if i < len(components)-1: 输出边 (start + n-1, start + n) # 桥 start += n这样我们就能在 内构造出任意 的图。
- 1
信息
- ID
- 4390
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者