1. 程式人生 > >Tarjan演算法三大應用之強連通分量

Tarjan演算法三大應用之強連通分量

Tarjan是一個對圖的分析的強有力的演算法,主要應用有:有向圖的強連通分量、無向圖的割點橋與雙連通分量、LCA(最近公共祖先)

基本概念

下面主要介紹tarjan演算法在強連通分量中的應用。

首先我們需要知道強連通是有向圖特有的概念,如果一個有向圖中任意兩點之間都是相互可達的那麼稱這個圖為強連通圖。一個圖的極大連通子圖稱為改圖的強連通分量。

Tarjan演算法求解強連通分量

通過Tarjan演算法可以得到每個點屬於哪個連通分量。

我們可以先初步把Tarjan演算法看成是一個對圖進行深搜並結合棧對節點進行處理的演算法。

該演算法涉及到三個值:

  • dfn[i]:dfn[i]表示圖中的節點i在搜尋過程中的(訪問)次序號,是第幾個訪問到的,也叫做時間戳

    ,每個節點的時間戳都是不一樣的

  • low[i]:low[i]表示第i個節點的子樹能夠追溯到的最早的棧中節點的次序號

  • vis[i]:vis[i]值為1表示i在棧中,為0表示不在棧中。

    我們先大致瞭解了tarjan演算法是做什麼的以及裡面的符號約定,不太懂也沒關係,現在我們換一種方式來觀察這個演算法到底是做什麼的。

    我們始終應該明確的一點是我們要求的是每個點屬於哪個連通分量,其實上面的low[i]的值就表示的是點i和哪個點(這個點也被稱作根,但不一定是極小的根)是屬於同一個連通分量的。

    因為tarjan演算法本質上是一個DFS的過程,這個演算法可以看成是在一顆“搜尋樹上進行”(這裡說樹也不太準確,但不妨礙我們理解)

    我們以下圖為例:

這裡寫圖片描述

轉化成搜尋樹的形式就是

這裡寫圖片描述

可以看出整個搜尋的過程是1->2->3->5,每搜到一個就進棧(這個棧不是指用於DFS的棧,而是另外開的一個棧,用來存放被搜到的節點中還沒確定連通分量的節點)

搜到5之後繼續搜發現又搜到了2,這個時候我們發現成環了。這個環上時間戳最小的是節點2,那麼當前這個連通分量(環)的根就是dfn[2]。

回溯之後2、3、5節點的low值都為dfn[2]了,

然後繼續從2搜,發現又搜到1,而1的時間戳更小,所以以2為根連通分量將合併到以1為根的連通分量。

回溯後繼續從1搜搜到4,發現4沒有子節點也就是(low[4]==dfn[4]),4就是根節點,這個連通分量只有一個節點,所以以節點4為集合的一個極大連通分量。

再回溯,發現從1出發也沒有點可搜了,此時low[1]==dfn[1]說明此時1作為根節點的連通分量是個極大連通分量。

整個搜尋就完成了。

通過這個例子我們可以總結出演算法在搜尋時的規則:

從點u出發

1.如果從u出發沒有點可以搜了並且low[u]==dfn[u]:那麼說明我們已經遍歷了這個點所屬的連通分量並且這個點就是該連通分量的根(我們的演算法也保證了在搜尋過程中該連通分量上的每個點的low值都更新為該連通分量的根),由於該連通分量已經確定了,所以我們可以把以u點為根的連通分量從圖中刪掉。

2.如果搜到的下一個節點v未被訪問過(可以由dfn來判斷):那麼就把它進棧並從它出發進行深搜。

3.如果搜到的下一個點v被訪問過並且在棧中(也就是vis[i]=1,那些被訪問過但已經出棧的節點所在的連通分量已經確定了,所以可以忽略這些點):那麼說明從v到u這條鏈上的點都屬於一個連通分量(因為把(u,v)練下去就會成環),這個時候就應該更新每個節點的low值為這個連通分量中時間戳最小的點的low值,在回溯的過程中也不斷將這個最小的low值傳遞。

這些規則就是tarjan演算法的基本框架了,具體的演算法細節請見程式碼。

模板

const int MAXN=105;
int n;
int DFN[MAXN];
int LOW[MAXN];
int vis[MAXN];
int belong[MAXN];//belong[i]表示i屬於縮點後的哪個節點
int cnt;
int tot;
struct Edge
{
      int v;
      int next;
}edge[MAXN*MAXN];
int edgecount;
int head[MAXN];
void Init()
{
      edgecount=0;
      memset(head,-1,sizeof(head));
}
void Add_edge(int u,int v)
{
      edge[++edgecount].v=v;
      edge[edgecount].next=head[u];
      head[u]=edgecount;
}
stack<int > St;
void Tarjan(int u)//從節點x開始搜尋
{
     DFN[u]=LOW[u]=++tot;
     vis[u]=1;//為1表示在佇列裡面
     St.push(u);
     for(int k=head[u];k!=-1;k=edge[k].next)
     {

           int v=edge[k].v;
           if(!DFN[v])//還未訪問過
           {
                 Tarjan(v);
                 LOW[u]=min(LOW[u],LOW[v]);
           }
           else if(vis[v])//被訪問過,還在佇列裡
           {
                 LOW[u]=min(LOW[u],DFN[v]);
           }
     }
     if(LOW[u]==DFN[u])
     {
           int x;
           ++cnt;
           while(1)
           {
                 x=St.top();
                 St.pop();
                 vis[x]=0;
                 belong[x]=cnt;
                 if(x==u)break;
           }
     }
}
void Solve()
{
    tot=0;
    cnt=0;//縮點後的點數
    memset(DFN,0,sizeof(DFN));
    memset(LOW,0,sizeof(LOW));
    memset(vis,0,sizeof(vis));
    while(!St.empty()) St.pop();
    for(int i=1;i<=n;i++)
    {
          if(DFN[i]==0)Tarjan(i);
    }
}

應用

相關推薦

Tarjan演算法三大應用連通分量

Tarjan是一個對圖的分析的強有力的演算法,主要應用有:有向圖的強連通分量、無向圖的割點橋與雙連通分量、LCA(最近公共祖先) 基本概念 下面主要介紹tarjan演算法在強連通分量中的應用。 首先我們需要知道強連通是有向圖特有的概念,如果一個有向圖中

Tarjan演算法三大應用連通分量

基本概念 定義1: 割點集合:點集V′∈V,若G刪除了V′後不連通,但刪除了V′的任意真子集後G仍然連通,則稱V′為割點集合 割點:若某一結點就構成了割點集合,那麼稱此結點為割點或

超詳細Tarjan演算法總結,求連通分量,割點,割邊,有重邊的割邊

Tarjan是一個人,他一身中發明了很多演算法,就這幾個演算法最為出名。 1、求有向圖的強連通分量,那麼什麼是強連通分量呢,就是一個頂點集合,任意兩個頂點間都可以互相到達。一個頂點也是強聯通分量如果圖中任意兩點可以互相到達,則此圖強連通。下圖中頂點{1,0,2}屬於一個強聯

Tarjan三大演算法連通分量

簡介: 在之前的兩篇部落格中,我們詳細介紹了Tarjan大牛發明的用來求解割點、橋和雙連通分量的演算法,這次我們介紹一下強連通分量。 演算法: 這次的Tarjan演算法,可以用一次DFS把所有強連通分量找出來,依舊是用兩個時間戳和棧來實現。演算法的大體思路

POJ 2186 Popular Cows(圖論連通分量

強連通分量之於有向圖,與並查集之於無向圖,在概念上極其相似,都是尋找互相聯絡的小部分內容。 POJ 2186 Popular Cows Description Every cow's dream is to become the most popular cow in the herd.

Tarjan演算法連通分量

最近又學習了強連通分量的Tarjan求法,先是看了別人的許多部落格,才勉勉強強看懂,自己寫完部落格後感到十分顯然,也沒有表面上看的那麼高大上。 好了,轉入正題,先說說什麼是強連通分量: 有向圖強連通分量:在有向圖G中,如果兩個頂點vi,vj間(vi>vj)有一條從v

有向圖的連通分量Tarjan演算法

描述: To prove two sets A and B are equivalent, we can first prove A is a subset of B, and then prove B is a subset of A, so finally we go

連通連通圖、連通分量 Tarjan演算法

一、解釋 在有向圖G中,如果兩個頂點間至少存在一條互相可達路徑,稱兩個頂點強連通(strongly connected)。如果有向圖G的每兩個頂點都強連通,稱G是一個強連通圖。非強連通圖有向圖的極大強連通子圖,稱為強連通分量(strongly connecte

Tarjan三大演算法連通分量(雙連通分量

定義: 對於一個連通圖,如果任意兩點至少存在兩條點不重複路徑,則稱這個圖為點雙連通的(簡稱雙連通);如果任意兩點至少存在兩條邊不重複路徑,則稱該圖為邊雙連通的。點雙連通圖的定義等價於任意兩條邊都同在一個簡單環中,而邊雙連通圖的定義等價於任意一條邊至少在一個簡單

(轉)Tarjan應用:求割點/橋/縮點/連通分量/雙連通分量/LCA(最近公共祖先)

應用 說明 lca ref father 無向圖 沒有 經理 遠的 本文轉載自:http://hi.baidu.com/lydrainbowcat/item/f8a5ac223e092b52c28d591c 作者提示:在閱讀本文之前,請確保您已經理解並掌握了基本的T

Tarjan三大算法連通分量(雙連通分量) (轉載)

進行 ack clear 例題 min 路徑 ace 相關 重復 定義: 對於一個連通圖,如果任意兩點至少存在兩條點不重復路徑,則稱這個圖為點雙連通的(簡稱雙連通);如果任意兩點至少存在兩條邊不重復路徑,則稱該圖為邊雙連通的。點雙連通圖的定義等價於任意兩條邊都同在一個簡單

連通連通圖、連通分量 Tarjan算法

The 當前 one 自身 com name cxf 單個 con 原文地址:https://blog.csdn.net/qq_16234613/article/details/77431043 一、解釋 在有向圖G中,如果兩個頂點間至少存在一條互相可達路徑,稱兩個頂點強連

tarjan演算法入門(三)——有向圖的連通分量

一.概述. 強連通分量SCC是基於有向圖的一個概念,即“極大連通分量”.有向圖的強連通分量就是說一張圖G的子圖G',G'的每一個點u都可以遍歷到這張圖上的任意一個點v,且這張子圖G'極大,極大的意思可以參考雙連通分量的極大.   二.強連通分量與tarjan演算法. t

HDU1269迷宮城堡------------------用Tarjan演算法計算連通分量

Problem Description  為了訓練小希的方向感,Gardon建立了一座大城堡,裡面有N個房間(N<=10000)和M條通道(M<=100000),每個通道都是單向的,就是說若稱某通道連通了A房間和B房間,只說明可以通過這個通道由A房間到達B房間,但並不說明通過它

HDU1269 連通分量-tarjan演算法

題意就是在給定一個圖的情況下,問這個單向圖是不是強連通圖。 強連通圖的意思就是圖中任何一個點都可以到達另一個點。 分析:這道題是tarjan演算法求強連通分量的模板題,對於tarjan演算法求連通分

演算法模板】Tarjan連通分量

#include<iostream> #include<cstring> #include<stack> #include<vector> using namespace std; const int MAXN=1000+1

[圖] 3.2.2 Tarjan演算法-有向圖的連通分量

Tarjan演算法 【Tarjan演算法】基於對圖DFS的演算法,每個強連通分量為搜尋樹中的一棵子樹 【輔助資料結構】 DFN[u]:為節點u搜尋的次序編號(時間戳) Low[u]:u或u的子樹能夠追

201509-4 高速公路 tarjan連通分量演算法 O(V+E)

#include<iostream> #include<algorithm> #include<cstdlib> #include<cstdio> #include<cstring> #include<vector> #

數算實習 popular cow 連通分量tarjan演算法

popular cow 描述:有N頭牛。如果a喜歡b,b喜歡c,則a也會喜歡c。告訴你M個喜歡關係 ,比如(a,b)表示a喜歡b。問有多少頭牛是被所有牛都喜歡的。 N<= 10,000, M<= 50,000 樣例輸入 3 3 1 2 2 1 2

連通分量及縮點tarjan演算法解析

http://blog.csdn.net/justlovetao/article/details/6673602 有向圖強連通分量的Tarjan演算法 [有向圖強連通分量]在有向圖G中,如果兩個頂點間至少存在一條路徑,稱兩個頂點強連通(strongly connected)。如果有向圖G的每兩個頂點都強連通,