zoukankan      html  css  js  c++  java
  • 【学习整理】Tarjan:强连通分量+割点+割边

    Tarjan求强连通分量

    在一个有向图中,如果某两点间都有互相到达的路径,那么称中两个点强联通,如果任意两点都强联通,那么称这个图为强联通图;一个有向图的极大强联通子图称为强联通分量

    Tarjan  算法可以在 O(n+m)的时间内求出一个图的所有强联通分量。

    dfn(i) 表示进入结点 i 的时间

    low(i) 表示从 i 所能追溯到的栈中点的最早时间

    如果某个点 x 已经在栈中则更新  low[i]=min(low[i],dfn[x]);

    否则对 x 进行回溯,并在回溯后更新  low[i]=min(low[i],low[x]);

     

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<stack>
    using namespace std;
    
    int n,m,tot,ind,ans;
    int dfn[200005],low[200005],last[200005];
    bool ins[200005];
    stack<int> s;
    struct hh
    {
        int fr,to,next;
    }e[500005];
    void add(int fr,int to)
    {
        e[++tot].to=to;e[tot].fr=fr;
        e[tot].next=last[fr];
        last[fr]=tot;
    }
    void tarjan(int now)
    {
        int i,j;
        s.push(now);
        ins[now]=true;
        low[now]=dfn[now]=++dex;
        for(i=last[now];i;i=e[i].next)
            if(!dfn[e[i].to])
            {
                tarjan(e[i].to);
                low[now]=min(low[now],low[e[i].to]);
            }
            else if(ins[e[i].to])low[now]=min(low[now],dfn[e[i].to]);
                    
        if(dfn[now]==low[now])
        {
            cnt=0;
            do
            {
                j=s.top();s.pop();
                ins[j]=false;
                cnt++;
            }while(j!=now);
            ans=max(ans,cnt);
        }
    }
    int main()
    {
        int i,j,u,v;
        scanf("%d%d",&n,&m);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            add(u,v);
        }
        for(i=1;i<=n;i++)
            if(!dfn[i]) tarjan(i);
        printf("%d",ans);
        return 0;
    }

    Tarjan求割点

    在一个无向图中,如果删掉点 x 后图的连通块数量增加,则称点 x 为图的割点

    对于搜索树上的非根结点 x ,如果存在子节点 i 满足 low[i]$geq$dfn[x]  ,即 i 向上无法达到 x 的祖先,则 x 为割点。

    对于搜索树上的根节点x,若它的子节点数 geq2 ,则 x 为割点。

     

    void tarjan(int x,int fa)
    {
        int i,j;
        dfn[x]=low[x]=++dex;
        for(i=last[x];i;i=e[i].next)
        {
            ++t[x];
            if(!dfn[e[i].to])
            {
                tarjan(e[i].to,x);
                low[x]=min(low[x],low[e[i].to]);
                if(x==root&&t[x]>=2) opt[x]=true;
                else if(x!=root&&low[e[i].to]>=dfn[x]) opt[x]=true;
            }
            else if(e[i].to!=fa) low[x]=min(low[x],dfn[e[i].to]);
        }
    }

     

     

    Tarjan求割边

    对于当前结点 x,若邻接点中存在结点 y 满足 low[y]$	extgreater$dfn[x] ,则 (x,y) 为割边。

     

    void tarjan(int x,int fa)
    {
        int i,j;
        low[x]=dfn[x]=++dex;
        for(i=last[x];i;i=e[i].next)
            if(e[i].to!=fa)
            {
                if(dfn[e[i].to]) low[x]=min(low[x],dfn[e[i].to]);
                else
                {
                    tarjan(e[i].to,x);
                    low[x]=min(low[x],low[e[i].to]);
                    if(low[e[i].to]>dfn[x]) opt[e[i].id]=true;
                }
            }
    }

  • 相关阅读:
    6-5-1
    static的作用
    第五小题:北京某高校。。。。
    机票预订系统问题定义及可行性分析
    银行储蓄系统问题定义及可行性分析
    软件工程和计算机科学的区别
    中文编码--中国程序员之”银弹“?
    开博第一日
    【转载】大牛很通俗地介绍《信号与系统》
    matlab绘图简单笔记
  • 原文地址:https://www.cnblogs.com/yljiang/p/6052596.html
Copyright © 2011-2022 走看看