HDU 2767 至少添加都是边成强连通图

来源:互联网 发布:淘宝定制机箱有哪里家 编辑:程序博客网 时间:2024/05/23 13:21

题目大意:给定一张有向图,问最少添加几条边使得有向图成为一个强连通图。

跑一边tarjan,如果是联通的就输入0,没有边要加的  ,  顺便把图缩点 ;(这类题本博客做过,直接把以前思路贴上来)

要使缩点后的图成为强连通图,每个顶点最少要有一个入度(其他点连接它)和一个出度(它连接其他点),一条边又提供一个出度和一个入度。
所以可以通过统计没有入度的顶点数 noInDegree 和 没有出度的顶点数 noOutDegree。即对于每个缩点,少出度就添,少入度就添;
所需要添加的边数就是noInDegree和noOutDegree中的最大值。


#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=30000 ;const int M=55000 ;struct node{int u,v,next ;}edge[M] ;int head[N] ,low[N],dnf[N],stack[N],vis[N] ,belong[N];int in[N],to[N] ;int top  ,cnt,dep,sum;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){int x ;low[u]=dnf[u]=++dep ;stack[cnt++]=u ;vis[u]=1 ;for(int i=head[u] ;i!=-1;i=edge[i].next){  int v=edge[i].v ;  if(!dnf[v])  {       tarjan(v) ;     low[u] = min(low[u],low[v]) ;  }else if(vis[v])     low[u] = min(low[u],dnf[v]) ;}if(low[u]==dnf[u]){  sum++ ;  do  {      x=stack[--cnt] ;     belong[x] =sum ;     vis[x]=0;  }while(x!=u) ;}}int main(){ int  t,n,m,a,b;  scanf("%d",&t) ; while(t--) {    top = 0 ;     cnt=dep=sum = 0 ;    memset(head,-1,sizeof(head)) ;    memset(low,0,sizeof(low)) ;    memset(dnf,0,sizeof(dnf)) ;    memset(vis,0,sizeof(vis)) ;    memset(in,0,sizeof(in)) ;    memset(to,0,sizeof(to)) ;   scanf("%d%d",&n,&m) ;  if(m==0)     printf("%d\n",n) ;  else{        for(int i = 0 ; i < m ; i++)    {         scanf("%d%d",&a,&b) ;         add(a,b)  ;    }    for(int i  = 1 ; i <= n ; i++)    {   if(!dnf[i])       tarjan(i) ;        }  for(int i = 1 ; i <= n ; 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]]++ ;         to[belong[i]]++;       }   }      if(sum <= 1 )   printf("0\n") ; else {             int sum1=0,sum2=0;     for(int i = 1 ; i <= sum ; i++)     {         if(!in[i]) sum1++;         if(!to[i]) sum2++ ;      }   printf("%d\n",max(sum1,sum2)) ; }      } }  return 0;} 


0 0