Advertisement

强连通分量——[Kosaraju算法]

阅读量:

思路:

[Kosaraju算法]

Kosaraju算法由有向图及其逆图两次深度优先搜索(DFS)构成,在时间复杂度上同样为O(N+M)。该算法的具体步骤如下:

在有向图G中选择一个起始顶点后展开深度优先搜索,在所有邻接节点的探索彻底完成后(即当深度优先搜索函数返回),按照上述顺序将顶点进行排序。

对于有向 图G来说,在其 逆 图G'上执行深度 优先 搜索 。若此次 搜索未能覆盖该 有 向 图的所有 节 点,则应从那些未被覆盖且 最后 完成 搜索 的 节 点中选择重新 开始 。依次 在 逆 图中 进 行 深 度 优 先 搜索 ,直 到 所 有 节 点都被访问 完 成 。

模板:

复制代码
 #include<cstdio>  
    
 #include<cstring>  
    
 #include<algorithm>  
    
 #include<vector>  
    
 using namespace std;  
    
 const int maxn=1000+10;  
    
 int n,m;  
    
 vector<int> G[maxn], G2[maxn];//G存原图,G2存逆图  
    
 vector<int> S;  
    
 int vis[maxn],sccno[maxn],scc_cnt;  
    
 void dfs1(int u)  
    
 {  
    
     if(vis[u]) return ;  
    
     vis[u]=1;  
    
     for(int i=0;i<G[u].size();i++)
    
    
    
    
    AI写代码
复制代码
     dfs1(G[u][i]);  
    
    AI写代码
复制代码
    S.push_back(u);  //s[i]表示的是:依次保存最后完成搜索的点
    
    AI写代码
复制代码
  
    
 }  
    
 void dfs2(int u)  
    
 {  
    
     if(sccno[u]) return;  //还没有搜过
    
     sccno[u]=scc_cnt;  
    
     for(int i=0;i<G2[u].size();i++)dfs2(G2[u][i]);  
    
 }  
    
 void find_scc(int n)  
    
 {  
    
     scc_cnt=0;  
    
     S.clear();  
    
     memset(vis,0,sizeof(vis));  
    
     memset(sccno,0,sizeof(sccno));  
    
     for(int i=0;i<n;i++)dfs1(i);  
    
     for(int i=n-1;i>=0;i--)  
    
     if(!sccno[S[i]]){scc_cnt++; dfs2(S[i]);}  
    
 }  
    
 int main()  
    
 {  
    
     while(scanf("%d%d",&n,&m)==2&&n)  
    
     {  
    
     for(int i=0;i<n;i++)  
    
     {  
    
         G[i].clear();  
    
         G2[i].clear();  
    
     }  
    
     while(m--)  
    
     {  
    
         int u,v;  
    
         scanf("%d%d",&u,&v);  
    
         G[u].push_back(v);  
    
         G2[v].push_back(u);  
    
     }  
    
     find_scc(n);  
    
     for(int i=0;i<n;i++)  
    
         printf("%d号点属于%d分量\n",i,sccno[i]);  
    
     }  
    
 }  
    
 /* 
    
    
    
    
    AI写代码

全部评论 (0)

还没有任何评论哟~