強連通圖(tarjan)模板和詳解


來一道裸代碼。
輸入:
一個圖有向圖。
輸出:
它每個強連通分量。

這個圖就是剛才講的那個圖。一模一樣。

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

 

代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<algorithm>
#include<map>
#define maxn 200005
using namespace std;
struct node
{
    int v,next;  //v表示指向的點  next表示
}mp[1005];
int DFN[1005],LOW[1005];   //DFN[]作為這個點搜索的次序編號(時間戳)
                           //LOW[]作為每個點在這顆樹中的,最小的子樹的根,每次保證最小,like它的父親結點的時間戳這種感覺
int stack[1005],heads[1005],visit[1005],cnt,tot,index;
 // 棧          訪問順序    是否訪問        
void add(int x,int y)
{
   mp[++cnt].next=heads[x];
   mp[cnt].v=y;
   heads[x]=cnt;
   return ;
}
void tarjan(int x)
{
    DFN[x]=LOW[x]=++tot;  //初始化x
    stack[++index]=x;     //進棧
    visit[x]=1;           //表示x已經入棧
    for(int i=heads[x];i!=-1;i=mp[i].next){
        if(!DFN[mp[i].v])  //如果沒有被訪問
    {
       tarjan(mp[i].v);  //往下延伸就是遞歸
       LOW[x]=min(LOW[x],LOW[mp[i].v]);  //遞歸出來,比較誰是誰的兒子/父親,就是樹的對應關系,涉及到強連通分量子樹最小根的事情
    }
    else if(visit[mp[i].v]) //如果訪問過,並還在棧里
    {
        LOW[x]=min(LOW[x],DFN[mp[i].v]);  //比較誰是誰的兒子/父親。就是鏈接對應關系
    }
    }
    if(LOW[x]==DFN[x]){ //發現整個連通分量子樹里的最小根
        while(1)
    {
        cout<<stack[index]<<" ";
        visit[stack[index]]=0;
        index--;
        if(x==stack[index+1]) break; //出棧,並且輸出
    }
    cout<<endl;
  }
}
int main()
{
    memset(heads,-1,sizeof(heads));
    int n,m;
    cin>>n>>m;
    int x,y;
    for(int i=1;i<=m;i++)
    {
        cin>>x>>y;
        add(x,y);
    }
    for(int i=1;i<=n;i++)
    {
        if(!DFN[i])tarjan(i); //當這個點沒有訪問過,就從這個點開始,防止圖沒有走完
    }
    return 0;
}

 

 

還有各大理解網站:   (雜着看,就可以看懂)

http://blog.miskcoo.com/2016/07/tarjan-algorithm-strongly-connected-components

https://blog.csdn.net/mengxiang000000/article/details/51672725

https://www.cnblogs.com/yxysuanfa/p/7396057.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM