pku 2186
注意此题是单case,若想统计有几个连通分量可以根据belong数组进行操作。
#include<iostream>
#incldue
<string.h>
#include
<stdlib.h>
#include
<stdio.h>
#define N1 50005
using namespace std;
struct Edge
{
    
int a, b;
}edges[N1];
bool visited[N1];//深搜时候,记录节点是否被访问过
int N,M;
int end_order[N1];//记录深搜的时候,节点访问结束顺序
int index;
int first[N1]; //用于存储图,first[i]指向第一条起始节点为i的边
int belong[N1];//belong[i]记录节点i属于哪个强连通分量
int cnt[N1]; //cnt[i]记录节点i强连通分量中节点的数量
bool is_out[N1]; //is_out[i]记录第i个强连通分量是否有出边
int cmp1(const void *a, const void *b)
{
    
return ((Edge*)a)->a-((Edge*)b)->a;
}
int cmp2(const void *a, const void *b)
{
    
return ((Edge*)a)->b-((Edge*)b)->b;
}
void dfs1(int source)
{
    
if(visited[source]) return ;
    visited[source]
=true;
    
for(int i=first[source]; i<first[source+1]; i++)
        dfs1(edges[i].b);
    end_order[index
++]=source;//记录节点访问结束顺序
}
void dfs2(int source ,int k)
{
    
if(visited[source]) return ;
    visited[source]
=true;
    
for(int i=first[source]; i<first[source+1]; i++)
        dfs2(edges[i].a, k);
    belong[source]
=k;//记录节点所属的强连通分量
    cnt[k]++;//强连通分量内节点计数
}
int main()
{
    
int ans;
    scanf(
"%d %d"&N, &M);
    
for(int i=0; i<M; i++){
        scanf(
"%d %d"&edges[i].a, &edges[i].b);
        edges[i].a
--; edges[i].b--;
    }
    edges[M].a
=edges[M].b=-1//简化下面first数组的构建
    qsort(edges, M, sizeof(edges[0]), cmp1);
    
int last_source=0;
    first[last_source]
=0;
    
int k=0;
    
while(last_source<N){
        
if(edges[k].a==last_source) k++;
        
else first[++last_source]=k;
    }
    memset(visited, 
0sizeof(visited));
    index
=0;
    
for(int i=0; i<N; i++)
        dfs1(i);
    qsort(edges, M , 
sizeof(edges[0]), cmp2);
    last_source
=0;
    first[last_source]
=0;
    k
=0;
    
while(last_source<N){
        
if(edges[k].b==last_source) k++;
        
else first[++last_source]=k;
    }
    memset(visited, 
0sizeof(visited));
    memset(cnt, 
0sizeof(cnt));
    k
=0;
    
for(int i=index-1; i>=0; i--){
        
if(visited[end_order[i]]) continue;
        dfs2(end_order[i], k); 
//第二次搜索
        k++;
    }
    
for(int i=0; i<M; i++){//记录哪些强连通分量有出边
        if(belong[edges[i].a]!=belong[edges[i].b])
            is_out[belong[edges[i].a]]
=true;
    }
    
int no_out=0;
    
for(int i=0; i<k; i++){//统计无出边的强连通分量的个数
        if(!is_out[i]){
            no_out
++;
            ans
=cnt[i];
        }
    }
    
if(no_out==1)//输出
        printf("%d\n", ans);
    
else
        printf(
"0\n");

    
return 0;
}