初始强连通分量

推荐博客 : 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("\n");
    }  
}
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 
*/

 

posted @ 2018-04-21 17:16  楼主好菜啊  阅读(131)  评论(0编辑  收藏  举报