kuangbin专题 专题九 连通图 Strongly connected HDU - 4635

题目链接:https://vjudge.net/problem/HDU-4635

题目:有向图,给定若干个连通图,求最多还能添加几条边,添完边后,图仍然要满足

(1)是简单图,即没有重边或者自环

(2)不是有向强连通图

 

思路:我们可以这么想,n个顶点,一个有向图边数最多,就是有向完全图,则边数为n*(n-1)。

要满足不是强连通图,我们可以假设有一个tarjan缩成的点(scc),它不能到达其他所有点,或者其他所有点

不能到达它,假设这个scc有k个顶点,也就是说,k*(n-k)条边是不存在的,那么最大添加边数应该是  n*(n-1) - k*(n-k) - m(本来有的边) ----  ①

给定的图情况不确定,我们先进行tarjan缩点,分成若干个scc,每个scc中也记录各自scc中的顶点数,然后进行scc的入度出度统计。

为使添加的边能最多,我们选所有的入度为0或者出度为0的scc 套入 公式①,选最大即可。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <algorithm>
  4 using namespace std;
  5 
  6 typedef long long ll;
  7 const int N = (int)1e5+10;
  8 int n,m,tot,tim,scc,top;
  9 int head[N],dfn[N],low[N],scc_no[N],s[N],ins[N];
 10 struct node{
 11     int to;
 12     int nxt;
 13 }e[N];
 14 struct col{
 15     int ru;
 16     int chu;
 17     int cnt;
 18 }col[N];//强连通分量
 19 
 20 void init(){
 21     for(int i = 0; i <= n; ++i){
 22         head[i] = -1;
 23         col[i].ru = col[i].chu = dfn[i] = 0;
 24     }
 25     tot = tim = scc = 0;
 26 }
 27 
 28 inline void add(int u,int v){
 29     e[tot].to = v;
 30     e[tot].nxt = head[u];
 31     head[u] = tot++;
 32 }
 33 
 34 void tarjan(int now,int pre){
 35     dfn[now] = low[now] = ++tim;
 36     ins[now] = 1; s[top++] = now;
 37     int to;
 38     for(int o = head[now]; ~o; o = e[o].nxt){
 39         to = e[o].to;
 40      //   if(to == pre) continue;
 41         if(!dfn[to]){
 42             tarjan(to,now);
 43             low[now] = min(low[now],low[to]);
 44         }
 45         else if(ins[to]) low[now] = min(low[now],dfn[to]);
 46     }
 47 
 48     if(dfn[now] == low[now]){
 49         int x,cnt = 0;
 50         ++scc;
 51         do{
 52             x = s[--top];
 53             ins[x] = 0;
 54             scc_no[x] = scc;
 55             ++cnt;
 56         }while(now != x);
 57         col[scc].cnt = cnt;//每个强连通分量包含几个点
 58     }
 59 }
 60 
 61 //入度出度统计
 62 void du_cnt(){
 63     int to;
 64     for(int now = 1; now <= n; ++now){
 65         for(int o = head[now]; ~o; o = e[o].nxt){
 66             to = e[o].to;
 67             if(scc_no[to] == scc_no[now]) continue;
 68                 ++col[scc_no[to]].ru;
 69                 ++col[scc_no[now]].chu;
 70         }
 71     }
 72 }
 73 
 74 void solve(int _case){
 75     for(int i = 1; i <= n; ++i)
 76         if(!dfn[i]) tarjan(i,i);
 77         
 78     ll ans = (ll)n*(n-1) - m;
 79     ll useless = (1LL) << 60;
 80     du_cnt();
 81     for(int i = 1; i <= scc; ++i){
 82         if(!col[i].ru || !col[i].chu){
 83             useless = min(useless,(ll)col[i].cnt*(n-col[i].cnt));
 84         }
 85     }
 86     if(scc == 1) printf("Case %d: -1\n",_case);
 87     else printf("Case %d: %lld\n",_case,ans-useless);
 88 }
 89 
 90 int main(){
 91 
 92     int T,u,v;
 93     scanf("%d",&T);
 94     for(int i = 1; i <= T; ++i){
 95         scanf("%d%d",&n,&m);
 96         init();
 97         for(int x = 1; x <= m; ++x){
 98             scanf("%d%d",&u,&v);
 99             add(u,v);
100         }
101         solve(i);
102     }
103 
104     return 0;
105 }
posted @ 2020-01-17 14:27  SummerMingQAQ  阅读(356)  评论(0编辑  收藏  举报