好久没写tarjan了,写起来有点手生,还好1A了- -。

  题意:给定一个有向图,问最多添加多少条边,让它依然不是强连通图。

  分析:不妨考虑最大时候的临界状态(即再添加一条边就是强连通图的状态),假设这时候的边的数量是F,那么答案就是F-m(m是一开始边的数量)。因此,F越大,答案越大。那么,怎么考虑F的值呢?最后的状态一定是这样的:整个图不是强连通的,但是他的两个分部x和y都是强连通的,并且其中任意一个分量(不妨设其为x),到另外一个分量(y),x中的每一个点到y中的每一个点都有边,而且,y中的每一个点到x中的每一个点都没有边;另外,x和y内部任意两点间都是有边的。这样的话任意添加一条边都会使得原图变成一个强连通图(因为再添加边只能是y中一点到x一点,这样整个图中任意两点间都可达了)。那么我们不妨设x中点的个数为a,y中点的个数为b=n-a(共有n个点),因此F=a*(a-1)+b*(b-1)+a*b(x到y的边)。这样,ans=F-m,化简得到ans=n*n-a*b-n-m。对a和b进行基本不等式可知,他们相等时乘积最大,因此他们相差最大时ans最大(也可以直接枚举任意两个强连通分量来得到答案)。另外要注意的一点是,x和y必须一个有任意一个是入度或者出度为0的,这样的话,才能使得他们构造成为F的状态。还想提的一点是,一个点也能成为强连通分量。

  具体见代码:

  1 #include <stdio.h>
  2 #include <algorithm>
  3 #include <string.h>
  4 #include <vector>
  5 #include <map>
  6 #include <set>
  7 #include <queue>
  8 #include <iostream>
  9 #include <stdlib.h>
 10 #include <string>
 11 #include <stack>
 12 using namespace std;
 13 const int inf = 0x3f3f3f3f;
 14 typedef long long ll;
 15 typedef pair<int,int> pii;
 16 const int N = 100000 + 5;
 17 
 18 int n,m,dfs_clock,dfn[N],low[N];
 19 int belong[N],scc_cnt,cnt[N],in[N],out[N];
 20 stack<int> S;
 21 vector<int> G[N];
 22 
 23 void init()
 24 {
 25     for(int i=1;i<=n;i++) G[i].clear();
 26     dfs_clock = 0;
 27     memset(dfn,0,sizeof(dfn));
 28     memset(belong,0,sizeof(belong));
 29     scc_cnt = 0;
 30     memset(cnt,0,sizeof(cnt));
 31     memset(in,0,sizeof(in));
 32     memset(out,0,sizeof(out));
 33 }
 34 
 35 void tarjan(int u)
 36 {
 37     dfn[u]=low[u]=++dfs_clock;
 38     S.push(u);
 39     for(int i=0;i<G[u].size();i++)
 40     {
 41         int v = G[u][i];
 42         if(!dfn[v])
 43         {
 44             tarjan(v);
 45             low[u]=min(low[u],low[v]);
 46         }
 47         else if(!belong[v])
 48         {
 49             low[u]=min(low[u],dfn[v]);
 50         }
 51     }
 52     if(low[u]==dfn[u])
 53     {
 54         scc_cnt++;
 55         int num = 0;
 56         for(;;)
 57         {
 58             num ++;
 59             int x = S.top();S.pop();
 60             belong[x] = scc_cnt;
 61             if(x==u) break;
 62         }
 63         cnt[scc_cnt] = num;
 64     }
 65 }
 66 
 67 void solve()
 68 {
 69     for(int i=1;i<=n;i++)
 70     {
 71         if(!dfn[i]) tarjan(i);
 72     }
 73 
 74     for(int i=1;i<=n;i++)
 75     {
 76         int x = belong[i];
 77         for(int j=0;j<G[i].size();j++)
 78         {
 79             int v = G[i][j];
 80             if(belong[i] == belong[v]) continue;
 81 
 82             int y = belong[v];
 83             out[x]++;
 84             in[y]++;
 85         }
 86     }
 87 
 88     ll ans = 0;
 89     for(int i=1;i<=scc_cnt;i++)
 90     {
 91         if(in[i] && out[i]) continue;
 92 
 93         int a = cnt[i];
 94         int b = n-a;
 95         ans = max(ans,(ll)n*n-(ll)a*b-n-m);
 96     }
 97     if(scc_cnt == 1) ans = -1;
 98     cout << ans << endl;
 99 }
100 
101 int main()
102 {
103     int T;
104     scanf("%d",&T);
105     for(int kase=1;kase<=T;kase++)
106     {
107         init();
108         printf("Case %d: ",kase);
109         scanf("%d%d",&n,&m);
110         for(int i=1;i<=m;i++)
111         {
112             int u,v;
113             scanf("%d%d",&u,&v);
114             G[u].push_back(v);
115         }
116         solve();
117     }
118 }