hihoCoder #1343 Stable Members

题目大意\(\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)\) 以外的交点。

posted @ 2017-11-30 19:29  Pat  阅读(306)  评论(0编辑  收藏  举报