zoukankan      html  css  js  c++  java
  • tarjan求强连通分量(模板)

    https://www.luogu.org/problem/P2341

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=50010;
    int pre[maxn],other[maxn],last[maxn],l;
    int n,m;
    int dfn[maxn],low[maxn],ans[maxn],st[maxn],belong[maxn],cnt,top,qw;
    //dfn->dfs序,low是点上非树边指向的点(拥有最小的dfs序 ),st是一个栈,记录环上的点,belong是点所属于的环 
    void add(int x,int y)
    {
        l++;
        pre[l]=last[x];
        last[x]=l;
        other[l]=y;
    }
    int ru[maxn],chu[maxn];//入度,出度 
    void dfs(int x)
    {
        dfn[x]=low[x]=++cnt;//可以知道每个点都指向自己(low) 
        ru[x]=1;
        st[++top]=x;
        for(int p=last[x];p;p=pre[p])
        {
            int v=other[p];
            if(!dfn[v])
            {
                dfs(v);//此时v的信息已经更新完毕 
                low[x]=min(low[x],low[v]);//用儿子更新父亲 
            }
            else if(ru[v])//儿子不在环上,因为环上的点low是没有意义的 
            {
                low[x]=min(low[x],dfn[v]);
            }
        }
        if(dfn[x]==low[x])//说明这是一个环 
        {
            belong[x]=++qw;//qw是环的个数 
            while(1)
            {
                int y=st[top--];
                ru[y]=0;
                belong[y]=qw;
                ans[qw]++;
                if(x==y) break;
            }
        }
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            add(a,b);//时刻注意是有向边 
        }
        for(int i=1;i<=n;i++)
        {
            if(!dfn[i]) dfs(i);//此操作是防止图不连通 
        }
        for(int i=1;i<=n;i++)
        {
            for(int p=last[i];p;p=pre[p])
            {
                int v=other[p];
                if(belong[i]!=belong[v])//实际上可以把一个环看成一个点(子环就是一个点) 
                {
                    chu[belong[i]]++;//有向边 
                }
            }
        }
        int p=0;//因为要所有牛都喜欢,所以只允许一个环的出现 
        for(int i=1;i<=qw;i++)
        {
            if(!chu[i])
            {
                if(p!=0)
                {
                    printf("0
    ");
                    return 0;
                }
                p=i;
            }
        }
        printf("%d
    ",ans[p]);
        return 0;
    }
    
    /*
    tarjan求强连通分量;
    这个板子就是在一个有向图中,找到一个所有点直接或间接指向的一个点
    (实际上可以是一个环,可以想象一个有向环,上面有许多“枝条”,
    这样所有环上的点都直接或间接指向环上的点,然后所有枝条上的点都直接或间接指向环上的点;
    那么环上的点就是那些所有点都直接或间接指向的) 
    */
  • 相关阅读:
    python排序
    python中常用的九种数据预处理方法分享
    8089汇编 源程序
    8086汇编 栈操作
    8089汇编 运算符指令
    8089汇编 标志寄存器
    8086汇编 段寄存器
    8086汇编 Debug 使用
    8086汇编 CPU 寄存结构
    8086汇编 内存交互
  • 原文地址:https://www.cnblogs.com/WHFF521/p/11398450.html
Copyright © 2011-2022 走看看