POJ 2186

POJ 2186

POJ 2186

题目描述:给定一个有向图,求满足下列条件的点V的个数:其他点均能沿着有向边到达V。

首先,将图的极大强联通分量缩成一个点,这是因为只要该联通分量某一点满足上述条件,则整个联通分量满足条件。

然后,明确的一点是,缩点后的图必无环,否则,可将环上所有点也缩成一个点,与极大强联通分量矛盾。

最后,只要找到缩点后的图中无出度的点的个数,设为cnt, 若 cnt > 1 , 则必无满足条件的点,因为一个出度为

零的点无法到达另一个出度为零的点;若cnt = 1 , 则该点所对应的强联通分量的点的个数即为答案。

参考程序:


#include<iostream>

using namespace std;

const int maxn = 10005;
const int maxe = 50005;

struct node

    
int v,next;
}
;

node e[maxe];
int es, E , N ; 
int gh[maxn];

void ins(int vs, int vt )
{    
     e[es].v 
= vt , e[es].next=gh[vs] , gh[vs] = es ++ ;
}


int stack[maxn] , instack[maxn] ,low[maxn] ,dfn[maxn] , idx[maxn] , out[maxn] , ok[maxn] ;
int  cnt ,top , pnt ;

void tarjan( int v)
{
      
int i,j,k , w , u;
      dfn[v] 
= low[v] = ++ cnt  ;
      stack[
++top] = v;  instack[v] = 1
      
for( i = gh[v] ; i!=-1 ;  i = e[i].next)
      
{    
            w 
= e[i].v ; 
            
if(!dfn[w])
            
{   
                tarjan(w); 
                low[v] 
= min(low[w], low[v]); 
            }

            
else 
               
if(instack[w])  low[v] = min(low[v] , dfn[w]);
      }
      
      
if( dfn[v] == low[v])
      
{    
           
++ pnt ;
           
do {    u  = stack[top -- ] ;  instack[u] = 0 ; idx[u] = pnt ; ok[pnt] ++ ; 
           }
  while( u!=v); 
      }
  
}

      

int can()
{   
    
int i,j,k;
    
    cnt 
= top  = pnt = 0 ; 
    memset(dfn , 
0 , sizeof(dfn));    
    memset(ok ,
0 , sizeof(ok));
    
    
for( i = 1 ; i<=N ; ++i)
     
if!dfn[i] ) tarjan(i);
     
    
if(pnt == 1)  return N ;
    
    memset(
out0 , sizeof(out));
    
for( i = 1 ; i<=N ; ++i )
        
for( j = gh[i] ;j!=-1 ;j=e[j].next)
           
if( idx[ e[j].v ] != idx[i] ) out[ idx[i] ] ++ ;
   
   
int ret , num = 0 ;
   
for(i = 1 ;i<=pnt ; ++i) 
      
if!out[i] )  {  num ++ ; ret = i ;}
   
   
if(num == 0)  return N ;
   
if(num > 1)   return 0 ;
   
   
return ok[ret];
}
  
    
int main()
{   
    
int i,vs,vt;
    scanf(
"%d%d",&N,&E);
    es 
= 0  ;
    memset(gh , 
-1sizeof(gh));
    
for(i = 0 ; i<E ; ++i)
    
{   
         scanf(
"%d%d",&vs,&vt);
         ins(vs,vt);
    }

    cout
<<can()<<endl;
    
    
return 0;
}

你可能感兴趣的:(POJ 2186)