强连通分量

强连通分量:一个有向图内,若一个子图是强连通的,且满足极大性,则称它是原图的一个强连通分量。在将所有强连通分量缩为一个点后,即得到了一个DAG


Kosaraju算法:我们对原图进行一遍DFS,记录它结束的时间点,然后在反向图中从时间点从大到小DFS,每次DFS遍历的结点即在一个强连通分量中,时间复杂度为O(n+m)

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>

#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define sz(x) (int)(x.size())

using namespace std;

const int maxn=1000+10;

int n,m,k,x,y,sc[maxn];

vector<int> G[maxn],RG[maxn],vs;

bool vis[maxn];

void DFS(int k)
{
 vis[k]=1;
 rep(i,0,sz(G[k])-1)
  if (!vis[G[k][i]]) DFS(G[k][i]);
 vs.push_back(k); //记录结束时间
}

void RDFS(int k,int p)
{
 vis[k]=1,sc[k]=p; //记录所属连通分量
 rep(i,0,sz(RG[k])-1)
  if (!vis[RG[k][i]]) RDFS(RG[k][i],p);
}

void scc()
{
 memset(vis,0,sizeof(vis));
 rep(i,1,n) if (!vis[i]) DFS(i); //第一遍DFS
 
 memset(vis,0,sizeof(vis)),k=0;
 dep(i,sz(vs)-1,0)
  if (!vis[vs[i]]) RDFS(vs[i],++k); //第二遍反向DFS
}

int main()
{
 scanf("%d%d",&n,&m);

 rep(i,1,m)
 {
  scanf("%d%d",&x,&y);
  G[x].push_back(y); //正向图
  RG[y].push_back(x); //反向图
 }

 scc();

 rep(i,1,n) printf("%d -> %d\n",i,sc[i]);

 system("pause");
 return 0;
}

posted @ 2016-07-17 17:01  Krew  阅读(182)  评论(0)    收藏  举报