Strongly connected HDU

  1 //题意:
  2 //给你一个有向图,如果这个图是一个强连通图那就直接输出-1
  3 //否则,你就要找出来你最多能添加多少条边,在保证添加边之后的图依然不是一个强连通图的前提下
  4 //然后输出你最多能添加的边的数目
  5 //
  6 //题解:
  7 //1、判断是否是强连通图你可以看一下有几个点的low[x]==dfn[x],如果只有一个,那这个图就是一个强连通图
  8 //2、
  9 //假如我们有两个子图,我们可以让这两个子图中每一个图内都连上有向边(把子图内部连成完全图)。然后再在这两个子图之间连上一条有向边
 10 //这样的话它仍然不是一个强连通图,因为这两个图之间的边只能进不能出(即,图与图之间是用单向边连接的)
 11 //这个子图是什么?
 12 //这个子图就是缩点之后的点的数目,因为缩点之后肯定可以保证里面没有环。但是这个点可能是由许多点缩成的,这个点
 13 //内部就是一个子图,除了这个点之外所有点是另一个子图。
 14 //之后我们可以先让原图进行缩点,这样图中就没有了环,然后我们再找出来哪个点的出度等于1或者入读等于1
 15 //因为只有这样的点才是决定是否这个图能变成强连通图的关键
 16 //为什么要找出入或者入度为0的点,因为作为一个强连通图是没有任何一个点出度或入度为0(反证法)
 17 #include<stdio.h>
 18 #include<string.h>
 19 #include<iostream>
 20 #include<algorithm>
 21 #include<map>
 22 #include<math.h>
 23 #include<set>
 24 #include<vector>
 25 #include<queue>
 26 using namespace std;
 27 typedef long long ll;
 28 const int maxn=100005;
 29 const int mod=26;
 30 const int INF=0x3f3f3f3f;
 31 const int block=300;
 32 struct edge
 33 {
 34     ll u,v,next;
 35 } e[100005];
 36 ll dfn[maxn],low[maxn],stacks[maxn],belong[maxn],in[maxn],out[maxn],g[maxn];
 37 ll head[maxn],visit[maxn],cnt,tot,index,scc;
 38 void init()
 39 {
 40     memset(in,0,sizeof(in));
 41     memset(out,0,sizeof(out));
 42     memset(g,0,sizeof(g));
 43     memset(head,-1,sizeof(head));
 44     memset(low,0,sizeof(low));
 45     memset(dfn,0,sizeof(dfn));
 46     memset(visit,0,sizeof(visit));
 47     memset(belong,0,sizeof(belong));
 48     cnt=tot=index=scc=0;
 49 }
 50 void add_edge(ll x,ll y)
 51 {
 52     e[cnt].u=x;
 53     e[cnt].v=y;
 54     e[cnt].next=head[x];
 55     head[x]=cnt++;
 56 }
 57 ll tarjan(ll x)
 58 {
 59     dfn[x]=low[x]=++tot;
 60     stacks[++index]=x;
 61     visit[x]=1;
 62     for(ll i=head[x]; i!=-1; i=e[i].next)
 63     {
 64         if(!dfn[e[i].v])
 65         {
 66             tarjan(e[i].v);
 67             low[x]=min(low[x],low[e[i].v]);
 68         }
 69         else if(visit[e[i].v])
 70         {
 71             low[x]=min(low[x],dfn[e[i].v]);
 72         }
 73     }
 74     if(dfn[x]==low[x])
 75     {
 76         scc++;
 77         do
 78         {
 79             g[scc]++;
 80             visit[stacks[index]]=0;
 81             belong[stacks[index]]=scc;
 82             index--;
 83         }
 84         while(x!=stacks[index+1]);
 85     }
 86 }
 87 int main()
 88 {
 89     ll n,m,t,p=0;
 90     scanf("%lld",&t);
 91     while(t--)
 92     {
 93         init();
 94         scanf("%lld%lld",&n,&m);
 95         cnt=0;
 96         for(ll i=1; i<=n; ++i)
 97         {
 98             head[i]=-1;
 99             visit[i]=0;
100             dfn[i]=0;
101             low[i]=0;
102         }
103         ll mm=m;
104         while(mm--)
105         {
106             ll x,y;
107             scanf("%lld%lld",&x,&y);
108             add_edge(x,y);
109         }
110         ll flag=0;
111         for(ll i=1;i<=n;++i)
112         {
113             if(!dfn[i])
114                 tarjan(i);
115         }
116         if(scc==1)
117         {
118             printf("Case %lld: -1
",++p);
119         }
120         else
121         {
122             for(ll i=0; i<cnt; ++i)
123             {
124                 ll fx=belong[e[i].u];
125                 ll fy=belong[e[i].v];
126                 if(fx!=fy)
127                 {
128                     out[fx]++;
129                     in[fy]++;
130                 }
131             }
132             ll ans=0,sum=0;
133             for(ll i=1; i<=scc; ++i)
134             {
135                 if(in[i]==0 || out[i]==0)
136                 {
137                     sum=0;
138                     //printf("%lld**
",g[i]);
139                     ll temp=n-g[i];
140                     //printf("%lld*
",temp);
141                     sum+=temp*(temp-1);
142                     //printf("%lld**
",sum);
143                     sum+=g[i]*(g[i]-1);
144                     //printf("%lld***
",sum);
145                     sum+=g[i]*temp;
146                     //printf("%lld****
",sum);
147                     sum-=m;
148                     ans=max(ans,sum);
149                 }
150 
151             }
152             printf("Case %lld: %lld
",++p,ans);
153         }
154     }
155     return 0;
156 }

 连通图和完全图的区别:
n个顶点的完全图有n(n-1)/2条边;而连通图则不一定,但至少有n-1条边。举个例子,
四个顶点的完全图有6条边,也就是四条边加上2条对角线;而连通图可以只包含周围四条边就可以了。

原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/11673431.html