• 初始强连通分量


    推荐博客 : https://www.cnblogs.com/wozaixuexi/p/8321602.html

          https://blog.csdn.net/qq_34374664/article/details/77488976

    在学习这个算法前,要先知道 : 连通图,强连通图,强连通分量

    连通图 : 如果两个顶点可以相互到达,则称这两个点强连通

    强连通图如果有向图中每两个顶点都连通,则称此图是一个强连通图

    强连通分量 : 在一个有向图中,有一个子图,这个子图中的没两个点都满足强连通,我们就把这个子图叫做强连通分量。

    处理强连通问题有两种算法

     1 、 tarjin 算法

    这里面有两个关键的数组 , dfn[ ] 数组,意思是在dfs过程中,当前的这个节点是第几个被遍历到的点,其实就是个时间戳

    low[ ] 数组,每个点所在的这棵树种,最小子树的根

    当 dfn[ u] = low[ u ] 表示 u 或 u 的子树构成一个强连通分量。

    我们求强连通分量,最终我们想要得到的就是一个 DAG 图,在 Tarjin 中缩点,构成一个无环的有向图

    例题 :

    输入: 一个图有向图。

    输出: 它每个强连通分量。

    input:

    6 8

    1 3

    1 2

    2 4

    3 4

    3 5

    4 6

    4 1

    5 6

    output:

    6

    5

    3 4 2 1

    代码示例 :

    const int maxn = 1e5+10;
    
    vector<int>ve[maxn];
    vector<int>id[maxn]; // 强连通的编号
    int n, m;
    int dfn[maxn], low[maxn]; // 每个点在这棵树中,最小的子树的根
    int tot = 0, key = 0;
    int Stack[maxn], belong[maxn]; // 缩点
    bool instack[maxn];
    int scc; // 强连通分量的个数
    
    void tarjin(int x){
        low[x] = dfn[x] = ++key; // 注意是 ++在前,因为下面下面深搜的判断是为0表示没访问过的点,才去搜
        Stack[tot++] = x;
        instack[x] = true;
    
        for(int i = 0; i < ve[x].size(); i++){
            int to = ve[x][i];
            
            if (!dfn[to]) {
                tarjin(to);
                low[x] = min(low[x], low[to]);
            }
            else if (instack[to]){
                low[x] = min(low[x], dfn[to]);
            }
        } 
        if (low[x] == dfn[x]){
            scc++;
            int v;
            do{
                v = Stack[--tot];
                instack[v] = false;
                belong[v] = scc;
                id[scc].push_back(v);
                printf("%d ", v);
            }
            while(v != x); 
            printf("
    ");
        }  
    }
    int u[maxn], v[maxn], in[maxn];
    vector<int>ans;
    
    int main() {
        //freopen("in.txt", "r", stdin);
        //freopen("out.txt", "w", stdout);
        cin >> n >> m;
        int a, b;
        
        memset(dfn, 0, sizeof(dfn));
        memset(low, 0, sizeof(low));
        memset(instack, false, sizeof(instack));
        memset(in, 0, sizeof(in));
        for(int i = 1; i <= m; i++){
            scanf("%d%d", &u[i], &v[i]);
            ve[u[i]].push_back(v[i]);
        }
        for(int i = 1; i <= n; i++){
            if (!dfn[i]) tarjin(i);
        }
       
        //for(int i = 1; i <= n; i++) printf("%d ", belong[i]);    
        return 0;
    }
    /*
    6 8
    1 3
    1 2
    2 4
    3 4
    3 5
    4 6
    4 1
    5 6 
    */
    
    东北日出西边雨 道是无情却有情
  • 相关阅读:
    HDU 6043
    HDU 6033
    HDU 6041
    HDU 6050
    HDU 6053
    HDU 6055
    HDU 6045
    HDU 6044
    HDU 6040
    ZUFE 1035 字符宽度编码(字符串)
  • 原文地址:https://www.cnblogs.com/ccut-ry/p/8902316.html
Copyright © 2020-2023  润新知