• 强连通分量(Kosaraju)


    //P2002解题思路:
    //先求SCC,缩点后,转换为DAG(有向无环图)
    //在DAG上统计入度为0的scc数量即可
    
    //Kosaraju时间复杂度:O(N+E)
    //两次DFS,2N,图的转置E,共2N+E 
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn=500010;
    struct edge{ int t; edge *nxt; edge(int to, edge * next){ t=to, nxt=next; } };
    edge * h1[maxn], * h2[maxn];											//h2是反图 
    void add1(int u, int v){ h1[u]=new edge(v, h1[u]); }
    void add2(int u, int v){ h2[u]=new edge(v, h2[u]); }
    int n, m, v[maxn], st[maxn], st_k, sccno[maxn], scc_cnt, scc_indegree[maxn];
    
    void dfs1(int x)
    {
    	v[x]=1;
    	for(edge * p=h1[x]; p; p=p->nxt)	if(!v[p->t]) dfs1(p->t);
    	st[++st_k]=x;
    }
    
    void dfs2(int x)
    {
    	v[x]=1;
    	sccno[x]=scc_cnt;
    	for(edge * p=h2[x]; p; p=p->nxt)	if(!v[p->t]) dfs2(p->t);
    }
    
    void kosaraju()
    {
    	for(int i=1; i<=n; i++)	if(!v[i]) dfs1(i);
    	memset(v, 0, sizeof(v));
    	for(int i=st_k; i>=1; i--)
    		if(!v[st[i]]) scc_cnt++, dfs2(st[i]);
    }
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	for(int i=1, b, e; i<=m; i++)
    	{
    		scanf("%d%d", &b, &e);
    		if(b!=e)	add1(b, e), add2(e, b); 							//去除自环 
    	}
    	kosaraju();
    	for(int i=1; i<=n; i++)												//统计每个scc的入度 
    		for(edge *p=h1[i]; p; p=p->nxt)
    			if(sccno[i]!=sccno[p->t])	scc_indegree[sccno[p->t]]++;	//起点和终点不在一个scc中才统计入度 
    	int ans=0; 
    	for(int i=1; i<=scc_cnt; i++)		if(!scc_indegree[i]) ans++;		//统计入度为0的scc的个数 
    	printf("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    web.xml文件的作用
    GitHub上最火的40个Android开源项目
    iOS 开发者必不可少的 75 个工具,你都会了吗
    canvas小知识
    最全的PHP开发Android应用程序
    Android系统在超级终端下必会的命令大全(adb shell命令大全)
    Android adb shell命令大全
    如何制作和部署war包
    android学习视频(实战项目演练)
    s:iterator标签的使用
  • 原文地址:https://www.cnblogs.com/lfyzoi/p/10616749.html
Copyright © 2020-2023  润新知