【题解】Network

「CEOI2012」Network


Solution to Question

首先缩点(当然也可以不缩?),然后跑一遍 DFS 即可。

//w为联通分量里的节点个数
inline void dfs (const int &u) {
	ans1[u] = w[u];
	for (int v : G_scc[u])
		dfs(v), ans1[u] += ans1[v];
}

Solution to Question

观察缩完点后的图一定是保证无环的,又由于题目有个非常特殊的条件:图中有一个中心点 r,对于其它所有点,有且仅有一条路径可达。于是,缩完点后的图一定是一棵以 r 为根节点的

对于节点 u,它的子树中的节点想要到达其它子树,就必须往上爬,于是有了一个贪心的思路:「每一次连边都需要尽量往上连」。


注意这里的到达是指有且仅有一条路径,考虑下图情况:如果我们想从 CA 甚至更上面连边,此时由于 A,B 在同一个联通分量中,B 原来是可以达到 A 的,再连上这条边之后,B 就有 2 条路径可以到达 AA,B,C 又形成了一个新的环),是不符合题意的。

情况一

但是对于如下图「特例」,向上连的边,仅是“擦边”经过联通分量。此时这条边是可连的。

情况二


对于节点 u,它的子节点有如下两种情况:(下图均为缩完点后的图)

  • 所有节点都连接到 u,再由 u 连一条边向上。

  • 有且 仅有一条 边直接跳过 u,直接向上连边,且满足「特例」(见上)。

    「仅有一条」:因为如果有第二条边向上连,则会有两个环经过同一条路径(u 往上)。


实现

由于缩完点是一棵树,考虑用 edge[] 记录下每个节点往上的那条边起始点在原图中的编号。

建图时,加上:

edge[scc[v]] = make_pair(u, v), 

这样我们可以在 O(1) 的时间复杂度,判断相邻的三个连通分量 A,B,C,是否只经过位于中间的连通分量 B 中的一个点。

edge[B].second == edge[C].first

Summary

  1. 这道题需要考虑很多情况;
  2. 实现起来也还是有点难度。
posted @   CloudWings  阅读(47)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示