题意:有N头牛,选出最受欢迎的牛,其中有M对A B,表示牛A认为牛B比较受欢迎,问你有多少牛最受欢迎。
在学习强连通分支的Tarjan算法是,好多人提到这题时比较经典的强连通分支题,所以拿来练手了,熟悉一下Tarjan算法的实现过程。学习过程中还发现一篇讲解Tarjian算法很好的Blog,
其中有图一步一步的讲解了Tarjan实现的过程,http://www.byvoid.com/blog/scc-tarjan/
代码:
View Code
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> #include <queue> #include <stack> #define N 10004 #define M 50005 using namespace std ; struct node { int e ; int next ; }p[M] ; int node[N] ; int dfn[N] , low[N] , belong[N] ; int out[N] , cnt , f[N] ; int index , res ; int q[N] , top ; void add( int x , int y ) { p[cnt].e = y ; p[cnt].next = node[x] ; node[x] = cnt++ ; } void init() { cnt= 0 ;res =0 ; index = 1 ;top = 0 ; memset( node , -1 , sizeof( node )); memset( dfn , 0 , sizeof ( dfn )); memset( low , 0 ,sizeof ( low )); memset( belong , 0 , sizeof ( belong )); memset( out , 0 , sizeof ( out )); memset( f , 0 , sizeof ( f )); memset( q , 0 , sizeof ( q )); } int min ( int x , int y ) { return x < y ? x : y ; } void dfs( int i ) { int j ; dfn[i] = low[i] = index++ ; q[top++] = i ; f[i] = 1 ; for ( j = node[i] ; j != -1 ; j = p[j].next ) { int x = p[j].e ; if ( !dfn[x] ) { dfs( x ); low[i] = min( low[i] , low[x] ); } else if( f[x] ) low[i] = min( dfn[x] , low[i] ); } if ( dfn[i] == low[i] ) { int y ; res++ ; do { y = q[--top] ; f[y] = 0 ; belong[y] = res; }while ( y != i ); } } void find( int n ) { int i , j ; for ( i = 1 ; i <= n ; i++ ) { for( j = node[i] ; j != -1 ; j = p[j].next ) if ( belong[i] != belong[p[j].e] ) out[belong[i]]++ ; } int num , mark ; num = 0 ; for ( i = 1 ; i <= res ; i++ ) if ( !out[i] ) { num++; mark = i ; } if ( num == 1 ) { int sum = 0 ; for ( i = 1 ; i <= n ; i++ ) if ( belong[i] == mark ) sum++ ; cout<<sum<<endl; } else cout<<"0\n"; } int main() { int n , m , i , a , b ; while(cin>>n>>m ) { init(); for ( i = 1 ; i <= m ; i++ ) { cin>>a>>b ; add( a , b ); } for ( i = 1 ; i <= n ; i++ ) if ( !dfn[i] ) dfs( i ); find( n ); } return 0 ; }
接下来,继续学习强连通的其他算法。