• tarjan-无向图(求割点)


    一、基本概念

    1、割点:无向连通图中,如果删除某点后,图变成不连通,则称改点为割点。

    2、桥:无向连通图中,如果去掉某条边后,整张无向图会分成两部分(即整张图不连通),这样的一条边成为桥。

    3、点双连通分量:无割点的极大连通子图

            任意两点间都有⾄至少两条不不经过相同边的路径

    4、边双连通分量:无割边的极大连通子图

            任意两点间都有⾄至少两条(除起点和终点外)不不经过相同点的路径

    二、tarjan求割点

    1)当前节点为树根时,成为割点的条件是“要有多于一个子树”(如果只有一棵子树,去掉这个点也没有影响,如果有两颗子树,去掉这个点,两颗子树就不连通了)

    2)当前节点不是树根的时候,条件是“low [ v ] >= dfn [ u ] ”,也就是在u之后遍历的点,能够向上翻,最多到u。(如果能翻到u的上方,那就有环了,去掉u之后,图仍然连通。)所以,保证v向上翻最多到u才可以

    洛谷板子题

    #include<cstdio>
    #include<algorithm> 
    using namespace std;
    
    inline int read()
    {
        int sum = 0,p = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-')
                p = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            (sum *= 10) += ch - '0';
            ch = getchar();
        }
        return sum * p;
    }
    
    const int maxn = 20005,maxm = 100005;
    int n,m,tot;
    int dfn[maxn],low[maxn],tim;
    int cnt,head[maxn];
    struct edge
    {
        int nxt,to;
    }e[maxm * 2];
    bool mrk[maxn];
    
    void add(int x,int y)
    {
        e[++cnt].nxt = head[x];
        e[cnt].to = y;
        head[x] = cnt;
    }
    
    void tarjan(int u,int fa)
    {
        dfn[u] = low[u] = ++tim;
        int child = 0;
        for(int i = head[u];i;i = e[i].nxt)
        {
            int v = e[i].to;
            if(!dfn[v])
            {
                tarjan(v,fa);
                low[u] = min(low[u],low[v]);
                if(low[v] >= dfn[u] && u != fa)
                    mrk[u] = true;
                if(u == fa)
                    child++;
            }
            low[u] = min(low[u],dfn[v]);
        }
        if(child >= 2 && u == fa)
            mrk[u] = true;
    }
    
    int main()
    {
        n = read(),m = read();
        for(int i = 1;i <= m;i++)
        {
            int x = read(),y = read();
            add(x,y);
            add(y,x);
        }
        for(int i = 1;i <= n;i++)
            if(!dfn[i])
                tarjan(i,i);
        for(int i = 1;i <= n;i++)
            if(mrk[i])
                tot++;
        printf("%d
    ",tot);
        for(int i = 1;i <= n;i++)
            if(mrk[i])
                printf("%d ",i);
        return 0;
    }
  • 相关阅读:
    如何选择大数据应用程序
    Python字符和字符值(ASCII或Unicode码值)转换方法
    Python字符和字符值(ASCII或Unicode码值)转换方法
    论炒币者的自我修养
    论炒币者的自我修养
    区块链是什么,如何评价区块链
    C#封装C++DLL(特别是char*对应的string)
    C#文件夹和文件操作
    VS工程目标文件名设置
    double最大最小值宏定义
  • 原文地址:https://www.cnblogs.com/darlingroot/p/11221478.html
Copyright © 2020-2023  润新知