• 【图论】割点


    百度百科

    Definition&Solution

      在一个无向联通图中,如果删除一个点,该图变得不连通,那么该点称作该图的割点。注意,割点可能不止一个。

      对于无向不连通图,一个点是割点当且仅当它是它所在的联通分量的割点。

      特别的,如果一个连通分量只包含一个点X,那么点X为一个割点。

      对于一个图,求他的割点,只需要对每个连通分量进行dfs,在dfs树上,一个非根节点是割点当且仅当他的子树的反向边全部指向他的子树。如果使用low[i]来代表点i所能连接的最小dfs序的点,dfn代表该点的dfs序,一个非根节点i是割点当且仅当对于所有的to=edge[j].to,满足low[to]>=dfn[i]。在dfs过程中,易于顺手求出dfs序和low值。

      对于一个根节点,根节点是割点当且仅当它有两个及以上子树。

    Example

    lgP3388 【模板】割点(割顶)

    Description

    给出一个n个点,m条边的无向图,求图的割点。

    Input

    第一行输入n,m

    下面m行每行输入x,y表示x到y有一条边

    Output

    第一行输出割点个数

    第二行按照节点编号从小到大输出节点,用空格隔开

    Sample Input

    6 7
    1 2
    1 3
    1 4
    2 5
    3 5
    4 5
    5 6

    Sample Output

    1 
    5

    Solution

    板子题。

    Code

    #include<cstdio>
    #define maxn 100010
    #define maxm 200010
    
    inline void qr(int &x) {
        char ch=getchar(),lst=NULL;
        while(ch>'9'||ch<'0') lst=ch,ch=getchar();
        while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        if(lst=='-') x=-x;
    }
    
    template <typename T>
    inline T mmax(const T &a,const T &b) {if(a>b) return a;return b;}
    template <typename T>
    inline T mmin(const T &a,const T &b) {if(a<b) return a;return b;}
    template <typename T>
    inline T mabs(const T &a) {if(a>=0) return a;return -a;}
    
    template <typename T>
    inline void spaw(T &a,T &b) {T temp=a;a=b;b=temp;}
    
    int n,m,a,b;
    int ans[maxn],cnt;
    bool is_cut[maxn];
    
    struct Edge {
        int to,nxt;
    };
    Edge edge[maxm];int hd[maxn],ecnt;
    inline void cont(int from,int to) {
        edge[++ecnt].to=to;
        edge[ecnt].nxt=hd[from];
        hd[from]=ecnt;
    }
    
    int dfn[maxn],low[maxn],vistime;
    void tarjan(int,int);
    
    int main() {
        qr(n);qr(m);
        while(m--) {
            a=b=0;qr(a);qr(b);
            cont(a,b); cont(b,a);
        }
        for(int i=1;i<=n;++i) {
            if(!dfn[i]) tarjan(i,i);
            if(is_cut[i]) ans[++cnt]=i;
        }
        printf("%d
    ",cnt);
        for(int i=1;i<=cnt;++i) printf("%d ",ans[i]);
    }
    
    void tarjan(const int u,const int rt) {
        int v,cld=0;
        dfn[u]=low[u]=++vistime;
        for(int i=hd[u];i;i=edge[i].nxt) {
            v=edge[i].to;
            if(!dfn[v]) {
                tarjan(v,rt);
                low[u]=mmin(low[u],low[v]);
                if(u==rt) ++cld;
                else if(low[v]>=dfn[u]) is_cut[u]=true;
            }
            low[u]=mmin(low[u],dfn[v]);
        }
        if((rt==u)&&(cld>1)) is_cut[u]=true;
    }

    Summary

    tarjan算法有很多,不要混淆(tarjan爷牛逼

    区分代码中v和u,否则会死。

    区分代码中dfn和low。否则会死

  • 相关阅读:
    复杂报表的存储过程
    Jquery中使用setInterval和setTimeout
    Jquery EasyUi实战教程布局篇
    枚举enum
    myGeneration代码生成器
    带有分页的存储过程
    应用临时表的存储过程
    缓存类的写法
    HDU4706 Children's Day
    HDU4706 Children's Day
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/9389977.html
Copyright © 2020-2023  润新知