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, 
0 sizeof (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, 
0 sizeof (visited));
    memset(cnt, 
0 sizeof (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 ;
}