强连通分量
强连通分量:一个有向图内,若一个子图是强连通的,且满足极大性,则称它是原图的一个强连通分量。在将所有强连通分量缩为一个点后,即得到了一个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;
}
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号