Tarjan的強聯通分量

來源:互聯網
上載者:User

標籤:memset   mem   ==   資訊   space   ace   數組   head   記錄   

  求強聯通分量有很多種。 《C++資訊學奧賽一本通》  中講過一個dfs求強聯通分量的演算法Kosdaraju,為了騙字數我就待會簡單的說說。然而我們這篇文章的主體是Tarjan,所以我肯定說完之後再讚揚一下Tarjan大法好是不是

  首先我們講一下強聯通分量

  強聯通分量指的是圖的一個子圖。在這個子圖中,任意兩個節點都可以互相到達。從定義上我們就可以看出是一個有向圖來,因為任意一個無向圖都符合該定義。

  而它的標準定義是:有向圖中任意兩點都聯通的最大子圖。

                     

  咳咳,首先慶祝一下哈——本人部落格的第一張圖。繪圖曆時3分鐘。

  在咱們舉的例子中,可以看出1 、2 、3 、5 通過邊可以相互到達,它們算一個強聯通分量,但4卻被它們隔絕在外。可以看出,從4點出發不能到達任意一個點。所以它單個節點也算一個強聯通分量。所以圖中的強聯通分量有兩個:一個是1-2-3-5,一個是4。

  ok看完了強聯通分量是什麼我們就講一下Kosaraju。

  這個演算法的思路是,對圖進行DFS並記錄每個點的退出順序。再構造反圖(就是有向邊的方向全都反過來),按照退出順序的逆序DFS反圖,對得到的點進行染色即為強聯通分量。

  講完思路開始類比。以起點1為起點遍曆順序如下:

  [ 1 2 3 5 4  5 3 2 4 4 1 ]

  加粗斜體外帶底線的部分就是本圖的退出順序。

  於是我們得到這樣一個數組:[ 5 3 2 4 1 ] 。按照這個數組的逆序對反圖遍曆得到:

  [ 5 3 2 1 退出 4 退出 ]

  即得到要求的兩個強聯通分量。

  還要兩遍DFS,麻煩的一比。看我大Tarjan一遍DFS就能求出強聯通分量

  首先我們要明確Tarjan要用到的兩個數組:dfn[] 和 low[] 

  dfn指的是在DFS過程中訪問到該點的順序。從1開始DFS全圖,那麼1的dfn值就是1,2的dfn值是2,5的dfn值是4,4的dfn值是5。剩下的一個類推

  那麼low呢?low指的是如果逆著DFS序往前回溯,該節點最早是由哪個節點走過來的。

  比如在中2 、3 、5 、4 最早都是由1走過來的,所以它們的low值都是1

  下面貼出dfn和low的演算法

每次dfs(點u){

  dfn[u] = 進入 dfs() 函數的次數  (自己定義一個時間戳記錄 如 timee)

       枚舉與其相鄰的點v{

          如果 沒有 訪問過點v {   ( 就是dfs樹上的樹邊 )

        dfs(v);

        如果 v 能追溯 到 比“u 追溯到的最早的點” 更早的點;

        那麼 u 就能 通過 v 來追溯到 那個點;

        low[u]=min(low[u],low[v]);

      }

       如果 訪問過點v && v在棧中

       low[u]=min(low[u],dfn[v]); 

     }

  縮點

}

  上面那些虛擬碼是從偉大的GeneralLiu那裡帶過來的,在此先%%%

  然後  假設我們走到一個節點i,發現這個i不能繼續擴充了,也就是dfn[i]==low[i]

  於是我們開始往回走。往回走的過程中,我們就把和它一個分量的節點進行染色,給它們統一的標記。  最後統計有多少種不同的標記即是強聯通分量個數

  luogu的一道題燒錄光碟片非常好,可以用於練手。

  放代碼

#include<iostream>#include<cstring>using namespace std;int head[10000],num;struct Edge{    int next,to;}edge[100000];int stack[10000],top;int color[10000],cnt;int dfn[10000],low[10000];int ID;bool jd[10000];int vis[10000];inline void add(int from,int to){    edge[++num]={head[from],to};    head[from]=num;}void tarjan(int x){    dfn[x]=++ID;    low[x]=ID;    jd[x]=1;    stack[++top]=x;    for(int i=head[x];i;i=edge[i].next){        int to=edge[i].to;        if(!dfn[to]){            tarjan(to);            low[x]=min(low[x],low[to]);        }        else if(jd[to])    low[x]=min(low[x],dfn[to]);    }    if(dfn[x]==low[x]){        jd[x]=0;        color[x]=++cnt;        while(stack[top]!=x){            color[stack[top--]]=cnt;            jd[stack[top+1]]=0;            color[stack[top+1]]=cnt;        }        top--;    }    }int main(){    int n;    cin>>n;    int x;    for(int i=1;i<=n;++i){        while(cin>>x&&x!=0){            add(i,x);        }    }    for(int i=1;i<=n;++i){        if(!dfn[i])    tarjan(i);    }    memset(jd,0,sizeof(jd));    for(int i=1;i<=n;++i){        for(int j=head[i];j;j=edge[j].next){            if(color[i]!=color[edge[j].to]){                jd[color[edge[j].to]]=1;            }        }    }    int ans=0;    for(int i=1;i<=cnt;++i)    if(!jd[i])    ans++;    cout<<ans<<endl;    return 0;}

 

Tarjan的強聯通分量

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.