zoukankan      html  css  js  c++  java
  • 图论tarjan

    有向图的强连通分量

    强连通分量:在有向图G中,如果两个顶点vi,vj间有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。
    dfn在代表时间戳,而low代表该点可以到达的点的最小dfn值,当low等于dfn的时候,就说明找到了一个强连通分量

    code

    int n,m,idx,top,cnt;
    
    int dfn[maxn];      //这个点是第几个被访问的
    int low[maxn];      //这个点所能到的点的dfn的最小值
    bool vis[maxn];     //标记一个点是否在栈中
    int s[maxn];        //栈
    
    vector<int> a[maxn];        //图
    
    void tarjan(int u)
    {
        dfn[u] = low[u] = ++idx;
        s[++top] = u;
        vis[u] = 1;
        for(auto v : a[u])
        {
            if(!dfn[v])         //如果这个点还没被访问过
            {
                tarjan(v);
                low[u] = min(low[u],low[v]);    //回溯
            }
            else if(vis[v])     //如果这个点在栈内
            {
                low[u] = min(low[u],dfn[v]);
            }
        }
        if(dfn[u] == low[u])        //找到一组强连通分量,而且这一组强连通分量就是从s[top]到s[top]==u;
        {
            cnt++;      //记录强连通分量的个数
            while (s[top] != u)
            {   
                vis[s[top]] = 0;
                top--;
            }
            vis[s[top]] = 0;
            top--;
        }
    }
    

    例题

    https://www.luogu.com.cn/problem/P2863

    无向图的割点和桥

    无向连通图中,如果删除某点后,图变成不连通,则称该点为割点
    无向连通图中,如果删除某边后,图变成不连通,则称该边为桥

    割点

    一个顶点u是割点,当且仅当
    (1)u为树根,且u有多于一个子树(不然删除这个点,还是联通的)
    (2)u不为树根,且存在儿子v,使得dfn[u] <= low[v]

    vector<int> a[maxn];        //图
    
    int dfn[maxn];
    int low[maxn];
    bool cut[maxn];            //是否是割点
    int idx;
    
    void tarjan(int u,int fa)        //fa记录最开始的树根
    {
        dfn[u]=low[u]=++idx;
        int child = 0;                //根的儿子个数
        for(auto i : a[u])
        {
            if(!dfn[i])
            {
                tarjan(i,fa);
                low[u] = min(low[u],low[i]);
                if(low[i] >= dfn[u] && u != fa) cut[u] = 1;        //u是割点
                if(u == fa) child++;                               //求根节点的子树个数
            }
            low[u] = min(low[u],dfn[i]);
        }
        if(child >= 2 && u == fa) cut[u] = 1;        //u为树根且儿子个数大于等于2
    }
    

    一条边(u,v)是桥,当且仅当(u,v)为树枝边,且满足dfn(u) < low(v)(前提是其没有重边)

    vector<int> a[maxn];
    
    int dfn[maxn],low[maxn],fa[maxn],idx,ans;
    
    void tarjan(int u,int pre)
    {
        dfn[u] = low[u] = ++idx;
        fa[u] = pre;
        for(auto i : a[u])
        {
            if(!dfn[i])
            {
                tarjan(i,u);
                low[u] = min(low[u],low[i]);
                if (low[i] > dfn[u]) ans++;                  //这个是桥
            }
            else if(i != pre)
            {
                low[u] = min(low[u],dfn[i]);
            }
        }
    }
    

    参考博客

    初探tarjan算法
    https://blog.csdn.net/LanQiLi/article/details/85009526

  • 相关阅读:
    iOS设备后台播放音乐方法
    iOS 编译64位FFMPEG
    os8 location authorization 错误.
    IOS 使用新浪微博SDK
    IOS 解析歌词lrc
    IOS 通过button获取cell
    IOS 解析XML文档
    OC .(点)与->(箭头)用法区别
    黑苹果安装合集
    Hello,World
  • 原文地址:https://www.cnblogs.com/hezongdnf/p/12089953.html
Copyright © 2011-2022 走看看