您的位置:首页 > 其它

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

2018-01-19 16:32 381 查看
思路:

[Kosaraju算法] Kosaraju是基于对有向图及其逆图两次DFS的方法,其时间复杂度也是O(N+M)。kosaraju算法的步骤如下:(1)在有向图G上,从某个顶点出发进行DFS,并按其所有邻接点的搜索都完成(即退出DFS函数)的顺序将顶点排列起来。(2)在有向图G上,从最后完成搜索的顶点出发,在图G的逆图G’上进行DFS,若此次遍历不能访问到有向图中所有顶点,则从余下的顶点中最后完成搜索的那个顶点出发,继续做逆图中的DFS,直至有向图中的所有顶点都被访问到为止。每一次调用DFS作逆图中的遍历所访问到的顶点集便是有向图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++)
dfs1(G[u][i]);
S.push_back(u);  //s[i]表示的是:依次保存最后完成搜索的点
}
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]);
}
}
/*
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: