【強連通分量】:
有向圖強連通分量:
在有向圖g中,如果兩個頂點間至少存在一條路徑,稱兩個頂點強連通(strongly connected)。
如果有向圖g的每兩個頂點都強連通,則稱g是乙個強連通圖。
非強連通圖有向圖的極大強連通子圖,成為強連通分量(strongly connected components)。
直接根據定義,用雙向遍歷取交際的方法求強連通分量,時間複雜度為o(n^2+m)。更好的方法是kosaraju演算法或者tarjan演算法。
兩者的時間複雜度都是o(n+m)。本文介紹的是tarjan演算法。
tarjan演算法是基於對圖深度優先搜尋的演算法,每個強連通分量為搜尋樹中的一顆子樹。
搜尋時,把當前搜尋樹中未處理的節點加入乙個堆疊,回溯時可以盤對棧頂到棧中的節點是否為乙個強連通分量。
定義dfn(u)為節點u搜尋的次序編號(時間戳)。low(u)為u或者u的子樹能夠追溯到的最早的棧中的節點的次序號。
由定義可以得出:
low(u)= min ((u,v)為樹枝邊,u為v的父節點dfn(v),(u,v)為指向棧中節點的後向邊(非橫叉邊))
當dfn(u)=low(u)時,以u為根的搜尋子樹上所有節點是乙個強連通分量。
附**:
#include#include#include#include#define maxn 1010
using namespace std;
int n,m,c=1,top=1,d=1,s=0,ans=0;
int cstack[maxn],deep[maxn],low[maxn],head[maxn],colour[maxn],num[maxn];//deep陣列就是 時間戳dfn陣列,且用了陣列模擬的棧。。。
bool beque[maxn];
struct nodea[maxn*5];//前向星存圖
inline int read()
while(c>='0'&&c<='9')
return date*w;
}void add(int x,int y)
void work(int x)
else if(beque[t])
low[x]=min(low[x],deep[t]);
}if(low[x]>=deep[x])while(cstack[--top]!=x);
}}int main()
for(int i=1;i<=n;i++)
if(!deep[i])
work(i);
for(int i=1;i<=n;i++)
for(int i=1;i<=n;i++)
if(colour[i]==num[0])
ans++;
printf("%d\n",ans);//強連通分量中節點個數
for(int i=1;i<=n;i++)
if(colour[i]==num[0])
printf("%d ",i);//強連通分量中各個節點
return 0;
}
強連通分量 tarjan求強連通分量
雙dfs方法就是正dfs掃一遍,然後將邊反向dfs掃一遍。挑戰程式設計 上有說明。雙dfs 1 include 2 include 3 include 4 include 5 6using namespace std 7const int maxn 1e4 5 8 vector g maxn 圖的鄰...
tarjan求強連通分量
tarjan求強連通分量 我們知道,在有向圖g中,如果任意兩個頂點都是連通的 所謂連通就是兩個頂點都能互相到達 那麼這個圖就是強連通圖。非強連通圖的極大強連通子圖,被稱為強連通分量。那麼什麼是極大強連通子圖呢?舉個例子幫助理解一下 例如下面圖一所示,其中子圖就是乙個極大強連通子圖,子圖也是乙個極大強...
Tarjan求強連通分量
強連通分量可以用tarjan求 比兩遍dfn大概快30 定義乙個棧 把點壓進去,然後根據自己所能到的點,求出能到達的dfn序最小的點 由此得到從此點到low點中的點 在棧中 可以成為乙個強連通分量 具體實現是當x點滿足dfn low時,將棧中的點全部彈出至x點 可以證明每個點最多被彈出1次,每條邊最...