1. 程式人生 > >Kosaraju兩次深搜實現強連通分量

Kosaraju兩次深搜實現強連通分量

什麽 itl color 強連通 遍歷 for details 調用 基本

Kosaraju兩次深搜實現強連通分量

kosaraju算法進行兩次dfs,第一次在原圖上進行,並在結點遞歸調用返回時將結點壓入一個棧中,第二次dfs在原圖的逆圖上進行,並且初始點選擇棧中最上面的點,每次dfs所訪問的點構成一個強連通分量。

第一次看kosaraju算法的時候,我很不解,為什麽第二次dfs隨便遍歷一下就能找到一個強連通分量呢?後來才頓悟,這裏關鍵是選取的遍歷起始點的順序。這裏就要好好研究一下為什麽第一次遍歷能夠為第二次遍歷打下這麽神奇的基礎。其實第一次dfs的操作,非常像一個基礎的算法——拓補排序,對,操作基本是一樣的,只是這裏的目的不是得到每個結點的拓補有序序列,而是。。。。對,其實不難想到,是強連通分量的拓補有序序列


#include<iostream>
#include<memory.h>
using namespace std;
int n,m;
int tis,tit,tst;
int g[5000][5000];
int d[50000];
int ge[50000];
int vis[50000];
int t=0;
void dfs1(int v0)
{
    vis[v0]=1;
    for(int i=1;i<=n;i++)
    if(!vis[i]&&g[v0][i])dfs1(i);
    d[++t]=v0;
}//top序 
void
dfs2(int v0) { vis[v0]=t;//v0屬於第t個強連通分量 ge[t]++; for(int i=1;i<=n;i++) if(!vis[i]&&g[i][v0])dfs2(i); } int main() { kosaraju: cin>>n>>m; for(int i=1;i<=m;i++) { cin>>tis>>tit>>tst; g[tis][tit]=tst;
if(tst==2)g[tit][tis]=tst; } for(int i=1;i<=n;i++)if(!vis[i])dfs1(i); memset(vis,0,sizeof(vis)); t=0; for(int i=n;i>=1;i--)if(!vis[d[i]])t++,dfs2(d[i]); int maxx=-0x7fffffff/2; int p; for(int i=1;i<=t+1;i++) { if(maxx<ge[i]) maxx=ge[i],p=i; } cout<<maxx<<endl; for(int i=1;i<=n;i++) { if(vis[i]==p) cout<<i<<" "; } }


摘自CSDN

Kosaraju兩次深搜實現強連通分量