题目大意$\newcommand{\SD}{\mathrm{SD}}$

给定一个 $n+1$ 个点的有向无环图,点从 $0$ 开始编号。无重边、自环,且从每个点 $u$ 都能到达 $0$ 号点。如果每条 $u\leadsto 0$ 路径($u\ne 0$)都经过点 $v$ ($v\ne 0$ 且 $v\ne u$),则称 $u$ 不稳定,否则称 $u$ 稳定。求稳定点的个数。

一个错误解法

先记录我的一个错误做法。将输入的图中的边全部反向,从 $0$ 号点开始 DFS。有向无环图在 DFS 的过程中不会出现回边(backward edge,也译作「后向边」),只有树边、前向边(forward edge)和侧向边(cross edge,也译作「横叉边」)。点 $u$ 稳定等价于「存在两条点不相交的 $0\leadsto u$ 路径」。而这个条件要是满足,那么必然出现连向 $u$ 的前向边或侧向边。在 DFS 的过程中,当发现有前向边或侧向边连向 $u$ 时,就检查当前这条 $0\leadsto u$ 路径和之前找到的完全由树边构成 $0\leadsto u$ 路径是否交叉,若无交叉,则 $u$ 稳定。可以通过类似 Tarjan 离线 LCA 算法的思路来判断上述两路径是否交叉,只要判断 $u$ 和 $0$ 是否在一个集合中(并查集),若在同一个集合中则无交叉。

代码:

#include <bits/stdc++.h>
#define rep(n) for(size_t __i = 0, __j=(n); __i < __j; ++__i)
#define rep2(i,n) for(size_t (i)=0, _i=n;(i)<_i;(i)++)
#define rep3(i,b,e) for(size_t i =(b); (i)<(e); (i)++)
#define ran(i,b,e) for(size_t (i)=(b); (i)<(e); (i)++)
#define drep2(i,n) for(size_t (i)=(n)-1; (i)>=0; (i)--)
using namespace std;
using ll=long long;
const size_t N=size_t(1e5+5); vector<size_t> g[N]; bool is_stable[N]; size_t fa[N]; size_t root(size_t x){
return x==fa[x]?x:fa[x]=root(fa[x]);
}
void unite(size_t x, size_t y){
x=root(x);
y=root(y);
fa[x]=y;
} bool vis[N];
void dfs(size_t u){
vis[u]=true;
for(auto v:g[u]) {
if (!vis[v]){
dfs(v);
unite(v,u);
}
else if (root(v) == 0) is_stable[v] = true;
}
} int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
size_t n;
cin>>n;
ran(i,1,n){
fa[i]=i; // init
size_t k;
cin>>k;
rep(k){
size_t x;
cin>>x;
g[x].push_back(i);
}
}
dfs(0);
for(auto x:g[0]) is_stable[x]=true;
int ans=0;
ran(i,1,n) ans+=is_stable[i];
cout<<ans<<'\n';
return 0;
}

这个做法是错的,下面给出一个反例:

节点编号也是节点的访问顺序。这个做法将 $3$ 号节点判为不稳定的。

题解上的做法

这道题我没想出正解。


仍考虑输入的图。

如果每条 $u\leadsto 0$ 路径($u\ne 0$)都经过 $v$ ($v\ne 0$ 且 $v\ne u$),则称 $v$ 是 $u$ 的支配点(dominator)。若 $v$ 是 $u$ 的支配点且 $v$ 是稳定的,则称 $v$ 为 $u$ 的稳定支配点(stable dominator)。

不难证明,支配点有下述性质:

性质 1

$u$ 的支配点可能不唯一,但一定分布在某条链上。

这个性质根据定义很容易证明。

性质 2

设 $v_1$、$v_2$ 是 $u$ 的两个支配点,那么或者 $v_1$ 是 $v_2$ 的支配点,或者 $v_2$ 是 $v_1$ 的支配点。

证明:

不失一般性,假设存在路径 $P\colon u\leadsto v_1\leadsto v_2\leadsto 0$ ,则必有 $v_2$ 是 $v_1$ 的支配点。若不然,即存在路径 $P'\colon v_1\leadsto 0$ 满足 $v_2$ 不在 $P'$ 上,从而 $v_2$ 也不是 $u$ 的支配点。

性质 3

若 $u$ 是不稳定的,则 $u$ 有唯一的稳定支配点。

证明:

用 $d(u)$ 表示 $u$ 到 $0$ 的最短距离。满足 $d(v)=1$ 的点 $v$ 必定是稳定的。

若 $v$ 是 $u$ 的支配点则必有 $d(v) < d(u)$ 。

由于 $u$ 的支配点的支配点也是 $u$ 的支配点,所以 $u$ 的稳定支配点必然存在。

$u$ 的稳定支配点是 $u$ 的所有支配点中距离 $0$ 号点最近的那个点。

又根据性质 $2$ 可知 $u$ 的稳定支配点唯一。

若 $u$ 不稳定,用 $\SD(u)$ 表示 $u$ 的稳定支配点。

可以证明下述定理

定理 1

$u\ne 0$ 是稳定的当且仅当:

(1) 存在弧 $(u,0)$;或者

(2) 存在两条「点(除 $u$ 外)不相交」的路径 $u\leadsto v_1$ 和 $u\leadsto v_2$ 满足 $v_1$ 和 $v_2$ 都是稳定的。

必要性是显然的,条件(2)的充分性也很容易证明。


若图中存在 $u\leadsto v$ 路径则称 $v$ 为 $u$ 的后继(successor),若图中存在弧 $(u,v)$ 则称 $v$ 为 $u$ 的直接后继(direct successor)。

具体实现就是:将图上的点拓扑排序,按照拓扑排序的逆顺序依次(根据定理 1)判断每个点是否稳定。定理 1 中的第二个条件中的 $v_1$、$v_2$ 包括:

  • $u$ 的稳定直接后继,
  • $\SD(v)$:$v$ 是 $u$ 的不稳定直接后继。

下面证明

性质 4

设 $v_1$、$v_2$ 是 $u$ 的两个不稳定的直接后继。若 $\SD(v_1)\ne SD(v_2)$,则存在两条点不相交的路径 $v_1\leadsto \SD(v_1)$ 和 $v_2\leadsto \SD(v_2)$ 。

证明:

反证法。

设 $P_1$ 是某一条 $v_1\leadsto \SD(v_1)$ 路径,令 $P_2$ 是任意一条 $v_2 \leadsto \SD(v_2)$ 路径,将路径 $P_1$、$P_2$ 上的交集记作 $V$($V \ne \emptyset$),将 $V$ 中「拓扑序最小的点」和「拓扑序最大的点」分别记为 $s(V)$ 和 $t(V)$ 。由于 $\SD(v_1)$ 是 $v_1$ 的支配点,可知 $\SD(v_1)\in V$,否则路径 $v_1 \xrightarrow{P_1} s(V)\xrightarrow{P_2} t(V) \xrightarrow{P_2} \SD(v_2)\leadsto 0$ 是一条不经过 $\SD(v_1)$ 的路径,这与 $\SD(v_1)$ 是 $v_1$ 的支配点矛盾!故 $P_2$ 经过点 $\SD(v_1)$ 。$P_2$ 是任意选取的,因而 $\SD(v_1)\ne \SD(v_2)$ 也是 $v_2$ 的稳定支配点,这又与性质 3 矛盾!所以假设不成立。

图中绿色路径表示 $P_1$,蓝色路径表示 $P_2$ 。

上述证明中有一个不严密的地方,即 $\SD(v_2)\leadsto 0$ 路径可能与 $P_1$ 相交;下面加以完善。

假设任意 $\SD(v_2)\leadsto 0$ 路径都与路径 $P_1$ 有交点;由于 $\SD(v_2)$ 是稳定的,存在一条不经过点 $\SD(v_1)$ 的 $\SD(v_2)\leadsto 0$ 路径 $P^*$,设 $w\ne\SD(v_1)$ 是 $P_1$ 与 $P^*$ 的一个交点,则 $v_1\xrightarrow{P_1} w\xrightarrow{P^*} 0$ 也是一条不经过 $\SD(v_1)$ 的路径,同样可导出矛盾。另外,容易证明,任意 $SD(v_2)\leadsto 0$ 路径与 $P_2$ 都没有除 $\SD(v_2)$ 以外的交点。

hihoCoder #1343 Stable Members的更多相关文章

  1. hihocoder 1343 : Stable Members【拓扑排序】

    hihocoder #1343:题目 解释:一个学习小组,一共有N个学员,一个主管.每个学员都有自己的导师(一个或者多个),导师可以是其他学员也可以是主管.每周学员都要把自己的学习报告和收到的报告提交 ...

  2. hihoCoder1343 : Stable Members【BFS拓扑排序】

    题目链接:https://hihocoder.com/problemset/problem/1343 #1343 : Stable Members 时间限制:10000ms 单点时限:1000ms 内 ...

  3. scala 2.11.x/spec/03-types.md

    scala/spec/03-types.md title: Types layout: default chapter: 3 --- Types Type ::= FunctionArgTypes ' ...

  4. HDOJ 1914 The Stable Marriage Problem

    rt 稳定婚姻匹配问题 The Stable Marriage Problem Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 6553 ...

  5. 【POJ 3487】 The Stable Marriage Problem (稳定婚姻问题)

    The Stable Marriage Problem   Description The stable marriage problem consists of matching members o ...

  6. [POJ 3487]The Stable Marriage Problem

    Description The stable marriage problem consists of matching members of two different sets according ...

  7. POJ 3487 The Stable Marriage Problem(稳定婚姻问题 模版题)

    Description The stable marriage problem consists of matching members of two different sets according ...

  8. 龙芯 3A4000 安装 Debian stable

    2022-01-17 版权声明:原创文章,未经博主允许不得转载 3A5000 开始,龙芯转向 loongarch ,新的架构虽然甩掉了历史包袱,但也需要一段时间来积累生态.在这半年多的时间里, loo ...

  9. AutoMapper:Unmapped members were found. Review the types and members below. Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type

    异常处理汇总-后端系列 http://www.cnblogs.com/dunitian/p/4523006.html 应用场景:ViewModel==>Mode映射的时候出错 AutoMappe ...

随机推荐

  1. [VC]关于ocx控件的自己编写的dll问题

    要是无法删除c:windows/cownloadprogrames下的文件时可以关掉所有的浏览器,然后在internate----程序---管理 加载项里 先把那个加载项 更新一下,或者禁用一下,或者 ...

  2. string 空值

    string str; string mystr = ""; 则 str == mystr;

  3. javaweb基础(22)_Servlet+JSP+JavaBean实战登陆

    一.Servlet+JSP+JavaBean开发模式(MVC)介绍 Servlet+JSP+JavaBean模式(MVC)适合开发复杂的web应用,在这种模式下,servlet负责处理用户请求,jsp ...

  4. 01_3_查询指定id的单个对象

    01_3_查询指定id的单个对象 1. 映射文件配置如下信息 <select id="selectStudentById" resultClass="Student ...

  5. Nginx正向代理代理http和https服务

    Nginx正向代理代理http和https服务 1. 背景需求 通过Nginx正向代理,去访问外网.可实现局域网不能访问外网的能力,以及防止在上网行为上,留下访问痕迹. 2. 安装配置 2.1安装 w ...

  6. skynet 学习笔记-sproto模块(2)

    云风在skynet中继承了sproto的传输协议,对比protobuf的好处是,能明文看到传输内容,而且skynet不需要protobuf这么功能,所以云风也建议在lua层使用sproto来作为sky ...

  7. Unity3d 中键值监听方法

    unity3d的api中没有负责监听键值的方法,不过unity的input类是通过c#类获取各类监听事件,所以我们可以通过c#类监听,方法如下: void OnGUI() { Event e = Ev ...

  8. 手机web网页的设计

      Viewport(视口) 1.视口概念 描述:视口,就是视图窗口的简称,页面中视口大小实际上就是html元素的显示大小 说明:页面想要在移动端加载必须进行视口适配 如果不对页面进行调整,默认页面在 ...

  9. (70)zabbix telnet监控类型

    概述 zabbix监控的方式很多,例如前面讲到的agent.snmp以及后续后续要讲到ssh和今天要讲到的telnet.流程很简单,创建item-->配置ip.用户.密码.端口.脚本->z ...

  10. python-面试常用 --变量、内存管理(小整数池,引用计数)

    执行Python程序的两种方法 第一种:交互式(jupyter就是对这种进行了封装) 优点:直接给出结果 缺点:无法保存 第二种:命令行式,通过Python解释器输入文本(pycharm对这种进行了封 ...