poj 2375 (强连通分量缩点max(入度,出度))



题意:给定一个滑雪场,每个点能向周围4个点高度小于等于这个点的点滑,现在要建电缆,使得任意两点都有路径互相可达,问最少需要几条电缆

思路:强连通缩点,每个点就是一个点,能走的建边,缩点后找入度出度为0的个数的最大值就是答案,注意一开始就强连通了答案应该是0


#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N= 300000 ;
const int M= 2222222 ;
const int dx[] = {-1, 1, 0, 0};  
const int dy[] = {0, 0, -1, 1}; 
struct node
{
	int  u ,  v , next ;
}edge[M] ;
int head[N],vist[N],low[N],dfn[N],belong[N],stack[N],g[505][505] ,out[N],in[N];
int top , sum , cnt , dep , n,m ;

int cheak(int i , int  j)
{
	 if( i >= 0 && i < n && j >= 0 && j<m) return 1;
	   return 0;
} 

void add(int u ,int v)  
 {  
      edge[top].u=u;  
      edge[top].v=v;  
      edge[top].next=head[u];  
      head[u]=top++;  
 }  
   
 void tarjan(int u )  
 {  
     low[u]=dfn[u]=++dep;  
     stack[cnt++]=u;  
     vist[u]=1;  
     for(int i = head[u] ; i!=-1 ; i=edge[i].next)  
     {  
              int  v= edge[i].v ;  
               if(!dfn[v])  
               {  
                      tarjan(v) ;  
                      low[u] = min(  low[u] , low[v] ) ;   
               }else if(vist[v])  
                 low[u] = min(  low[u] , dfn[v] );   
     }  
    if(low[u] == dfn[u])  
    {  
          int x;  
          sum++ ;  
          do  
          {  
                x=stack[--cnt] ;  
                 vist[x] = 0 ;  
                belong[x]=sum;      
          }while(x!=u) ;  
    }  
 }  
   
int main()
{     int  w =0;
	  while(~scanf("%d%d",&m,&n))
	  {
	  	    top =0 ; sum = 0 ;dep = 0 ;cnt = 0 ;
	  	    memset(head,-1,sizeof(head)) ;
	  	    memset(low,0,sizeof(low)) ;
	  	    memset(dfn,0,sizeof(dfn)) ;
	  	    memset(vist,0,sizeof(vist)) ;
	  	    memset(out,0,sizeof(out));
	  	    memset(in,0,sizeof(in));
	  	    for(int i = 0 ; i < n ; i++)
	  	      for(int j = 0 ; j < m ; j++)
	  	         scanf("%d",&g[i][j]) ;
	  	    
			 for(int i = 0 ; i < n ; i++)
			  for(int j = 0 ; j < m ; j++)
			   for(int k = 0 ; k < 4 ; k++)
			    {
			    	  int xx = i + dx[k] ;
			    	  int yy = j + dy[k] ;
			    	  int u = i*m+j ,v=xx*m+yy ; 
			    	  if(cheak(xx,yy))
					  {     
			    	  	    if(g[i][j] >= g[xx][yy])
			    	  	    {
			    	  	    	   add(u,v);w++;
			    	  	    }
			    	  	    if(g[i][j] <= g[xx][yy])
			    	  	    {
			    	  	    	  add(v,u);w++;
			    	  	    }
			    	  }
			    }      
	  	  //  printf("%d\n",w);
		    for(int i = 0 ; i < n*m ; i++)
			      if(!dfn[i])
			        tarjan(i) ;
		 //   	printf("*%d* ",sum);
			for(int i = 0 ; i < n*m ; i++)
			  for(int j= head[i] ; j!=-1; j=edge[j].next)
			    {
			    	   int v = edge[j].v ; 
			    	   if(belong[i] != belong[v])
					   {
					      in[belong[v]]++ ;
					      out[belong[i]]++;
				       }
			    } 	
			if(sum <= 1 )    //刚开始强联通的    
			   printf("0\n") ;
			else
			{
				   int a=0,b=0;
				   for(int i = 1 ; i <= sum ; i++)
				    {
				      if(out[i] == 0)
				         a++ ;
				       if(in[i] == 0)
					     b++ ;   
				    }
				    printf("%d\n",max(a,b)) ;
			}    
			         
	  }
	return 0;
} 





你可能感兴趣的:(poj 2375 (强连通分量缩点max(入度,出度)))