zoukankan      html  css  js  c++  java
  • hihoCoder #1343 Stable Members

    题目大意$ ewcommand{SD}{mathrm{SD}}$

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

    一个错误解法

    先记录我的一个错误做法。将输入的图中的边全部反向,从 $0$ 号点开始 DFS。有向无环图在 DFS 的过程中不会出现回边(backward edge,也译作「后向边」),只有树边、前向边(forward edge)和侧向边(cross edge,也译作「横叉边」)。点 $u$ 稳定等价于「存在两条点不相交的 $0leadsto u$ 路径」。而这个条件要是满足,那么必然出现连向 $u$ 的前向边或侧向边。在 DFS 的过程中,当发现有前向边或侧向边连向 $u$ 时,就检查当前这条 $0leadsto u$ 路径和之前找到的完全由树边构成 $0leadsto 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<<'
    ';
        return 0;
    }
    

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

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

    题解上的做法

    这道题我没想出正解。


    仍考虑输入的图。
    如果每条 $uleadsto 0$ 路径($u e 0$)都经过 $v$ ($v e 0$ 且 $v e 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$ 的支配点。

    证明:
    不失一般性,假设存在路径 $Pcolon uleadsto v_1leadsto v_2leadsto 0$ ,则必有 $v_2$ 是 $v_1$ 的支配点。若不然,即存在路径 $P'colon v_1leadsto 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 e 0$ 是稳定的当且仅当:
    (1) 存在弧 $(u,0)$;或者
    (2) 存在两条「点(除 $u$ 外)不相交」的路径 $uleadsto v_1$ 和 $uleadsto v_2$ 满足 $v_1$ 和 $v_2$ 都是稳定的。

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


    若图中存在 $uleadsto 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) e SD(v_2)$,则存在两条点不相交的路径 $v_1leadsto SD(v_1)$ 和 $v_2leadsto SD(v_2)$ 。

    证明:
    反证法。
    设 $P_1$ 是某一条 $v_1leadsto SD(v_1)$ 路径,令 $P_2$ 是任意一条 $v_2 leadsto SD(v_2)$ 路径,将路径 $P_1$、$P_2$ 上的交集记作 $V$($V e 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) e 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 eSD(v_1)$ 是 $P_1$ 与 $P^*$ 的一个交点,则 $v_1xrightarrow{P_1} wxrightarrow{P^*} 0$ 也是一条不经过 $SD(v_1)$ 的路径,同样可导出矛盾。另外,容易证明,任意 $SD(v_2)leadsto 0$ 路径与 $P_2$ 都没有除 $SD(v_2)$ 以外的交点。

  • 相关阅读:
    接口 多态
    继承extends (特点、重写、覆盖、应用)抽象abstract(定义、特点、细节)
    0515 面向对象 类与对象、局部、成员变量、基本、引用类型、封装 private 和this 及应用
    Eclipse 快捷键
    Flutter Framework启动代码阅读
    Flutter Widget概览
    Flutter局部状态管理
    iconfont应用
    implicit_animations.dart阅读
    Flutter异常搜集方案
  • 原文地址:https://www.cnblogs.com/Patt/p/7928969.html
Copyright © 2011-2022 走看看