好久没写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 }