• Kosaraju算法——强连通分量


    ´有向图的极大强连通子图,称为强连通分量。
    ´子图指的是选取V的一个子集V’,以及E当中所有满足u,v∈V’的边集E’所指代的图.
    ´我们需要找出一幅有向图当中的所有强连通分量。
     
    ´一个最朴素的算法:
    ´构造一个传递闭包(也就是数组Aij表示i能否到达j),然后把Aij=Aji=1的节点置于同一个强连通分量当中
    ´这个算法的复杂度是O(n^3),优点是代码复杂度小,缺点是速度太慢了
     
    ´这个算法原理和上面的方法是类似的,如果A能到达B并且B能到达A,那么A和B在同一个强连通分量里面。
    ´也可以等同于说,如果原图与逆图中A都能到达B,那么A与B在同一个强连通分量里面。
     
    ´逆图,指的是将原本有向图的所有边的方向变成相反,也就是说原本从a到b的边变成从b到a。
     
    ´算法流程有三步:
    ´对原图进行DFS,求出每一个节点的结束时间戳(离开这个节点时访问了多少个节点);
    ´选择结束时间戳最晚的节点,在逆图中进行遍历,删除能遍历到的节点,这些节点构成一个强连通分量;
    ´如果还有顶点未删除,重复第二步;
    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn=100000+15;
    int n,m;
    vector <int> edge[maxn],rev[maxn];
    int tim,rank[maxn],ref[maxn];
    bool boo[maxn];
    int color[maxn],tot;
    int dfs1(int now)
    {
        if (boo[now]) return 0;
        boo[now]=true;
        for (int i=0;i<edge[now].size();dfs1(edge[now][i]),i++);
        rank[now]=++tim;
        ref[tim]=now;
        return 0;
    }
    int dfs2(int now)
    {
        if (color[now]!=0) return 0;
        color[now]=tot;
        for (int i=0;i<rev[now].size();dfs2(rev[now][i]),i++);
        return 0;
    }
    int main()
    {
        freopen("ko.in","r",stdin);
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            edge[x].push_back(y);
            rev[y].push_back(x);
            }
        for (int i=1;i<=n;i++)
         if (!boo[i]) dfs1(i);
        for (int i=n;i>=1;i--)
         if (color[ref[i]]==0)
         {
                tot++;
                dfs2(ref[i]);
                }
        for (int i=1;i<=n;i++) 
         printf("%d ",color[i]);
        return 0;
    }
  • 相关阅读:
    当td中文字过长时,显示为省略号
    清除页面缓存
    在dwr的调用类里获取请求信息
    解决利用hibernate连接mysql时无法插入汉字的问题
    MySql的数据库方言问题
    解决IE升级后必须以管理员运行的问题
    form表单里的button调用js函数
    EF多租户实例:演变为读写分离
    EF多租户实例:快速实现分库分表
    EF多租户实例:如何快速实现和同时支持多个DbContext
  • 原文地址:https://www.cnblogs.com/9pounds15pence/p/6349697.html
Copyright © 2020-2023  润新知