剛剛在算導上學會用兩次dfs求scc,終於過了前段時間群賽的乙個題。
題意:給定乙個有向圖,讓你求它是否為半連通圖(即對於圖中任意兩個頂點u,v 是否有u可以到達v或者v可以到達u)
解題思路:當時還不知道啥強連通分量,看了人家的一篇部落格,了解了下解題思路,就是先求強連通分量+縮點,得到縮點以後的dag(有向無環圖),然後對縮點以後的圖進行拓撲排序,如果有分叉則說明,原圖不是半連通的(即從分叉處往下的兩個分支,不能保證對於其中任意兩個節點之間可達)。
關於該演算法的正確性,算導上面證明的很清楚。
求scc的步驟為:
1. 對原圖進行dfs,求出每個結點的離開時間。
2. 按離開時間從後到前,對逆圖進行dfs,每次dfs所到達的結點就組成乙個強連通分量。(其實每個強連通分量可以看成乙個點,然後這些點能構成乙個dag,至於如何保持scc構成的dag,其實可以用乙個belong陣列,belong[v]表示v結點屬於哪乙個強連通分量,這樣在進行第二次dfs的時候如果搜尋到已經被訪問過的點上,並且該點在已經求出的強連通分量上,那麼就把scc[belong[w]][now]置1,表示以前求出的強連通分量到當前正在求的強連通分量有一條邊,不過我這裡沒想到這個好辦法,我是把每個強連通分量裡包含的頂點儲存下來,如果搜尋到已經訪問過的結點就去以前求出的強連通分量裡找該結點如果找到就在scc中新增一條邊)
按上述順序求出縮點以後的圖,進行拓撲排序:
1. 每次取出所有結點中入度為0的並且沒有被訪問過的結點,如果這樣的結點有多個,說明存在分支,則輸出no
2. 如果所有結點能按照1步驟進行排序,說明沒有分支,則輸出yes.
**如下:
#include#include#include#includeusing namespace std;
const int maxn = 1001;
int scc[maxn][maxn],vis[maxn],f[maxn],indeg[maxn],scccnt;
vectorsccv[maxn],g[maxn],gt[maxn];
bool find(int w,int i)}}
}}void scc(int n)//cac all scc
}}bool solve()//toposort
{ memset(indeg,0,sizeof(indeg));
for(int i=0;i
POJ 2762 強連通分量
剛剛在算導上學會用兩次dfs求scc,終於過了前段時間群賽的乙個題。題意 給定乙個有向圖,讓你求它是否為半連通圖 即對於圖中任意兩個頂點u,v 是否有u可以到達v或者v可以到達u 解題思路 當時還不知道啥強連通分量,看了人家的一篇部落格,了解了下解題思路,就是先求強連通分量 縮點,得到縮點以後的da...
poj 2762 強連通 判斷鏈
思路 首先當然是要縮點建新圖,由於題目要求是從u v或從v u連通,顯然是要求單連通了,也就是要求一條長鏈了,最後只需判斷鏈長是否等於新圖頂點個數即可,至於如何求一條鏈長,直接dfs即可,注意點就是dfs是要從入度為0的頂點開始。1 include2 include3 include4 includ...
強連通分量 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 圖的鄰...