3 3 3 1 2 2 3 3 1 3 3 1 2 2 3 1 3 6 6 1 2 2 3 3 1 4 5 5 6 6 4
Case 1: -1 Case 2: 1 Case 3: 15
题意:要求添加最多的边使得该图仍然不是强连通图。
思路:由于不是强连通图且边数最多,最后的图一定是分成两部x和y,x是完全图,y也是完全图,只有x到y的边没有y到x的边,假设X部有x个点,Y部有y个点,则x+y=n; 同时边数F=x*y+x*(x-1)+y*(y-1)=x*y+x^2+y^2+2*x*y-2*x*y-x-y=(x+y)^2-x*y-(x+y)=(x+y)*(x+y-1)-x*y=n*(n-1)-x*y;然后去掉已经有了的边m,则为答案; 由于x+y是定值,那么x与y相差越大则x*y越小,则-x*y越大。对于给定的有向图缩点,对于缩点后的每个点,如果它的出度或者入度为0,那么它才有可能成为X部或者Y部, 然后找出最大值即可。
#include <iostream> #include <stdio.h> #include <stdlib.h> #include<string.h> #include<algorithm> #include<math.h> #include<stack> #include<queue> using namespace std; typedef long long LL; const int N=100010; struct data { int to,next; } tu[N*2]; int head[N]; int ip; int dfn[N], low[N];///dfn[]表示深搜的步数,low[u]表示u或u的子树能够追溯到的最早的栈中节点的次序号 int sccno[N];///缩点数组,表示某个点的缩点值 int step, rd[N], cd[N];///入度出度数组 int scc_cnt;///强连通分量个数 void init() { ip=0; memset(head,-1,sizeof(head)); } void add(int u,int v) { tu[ip].to=v,tu[ip].next=head[u],head[u]=ip++; } vector<int> scc[N];///缩点 stack<int> S; void dfs(int u) { dfn[u] = low[u] = ++step; S.push(u); for (int i = head[u]; i !=-1; i=tu[i].next) { int v = tu[i].to; if (!dfn[v]) { dfs(v); low[u] = min(low[u], low[v]); } else if (!sccno[v]) low[u] = min(low[u], dfn[v]); } if (low[u] == dfn[u]) { scc_cnt += 1; scc[scc_cnt].clear(); while(1) { int x = S.top(); S.pop(); if (sccno[x] != scc_cnt) scc[scc_cnt].push_back(x); sccno[x] = scc_cnt; if (x == u) break; } } } void tarjan(int n) { memset(sccno, 0, sizeof(sccno)); memset(dfn, 0, sizeof(dfn)); step = scc_cnt = 0; for (int i = 1; i <=n; i++) if (!dfn[i]) dfs(i); } int T, n, m; int main() { scanf("%d", &T); for (int k = 1; k <= T; k++) { init(); scanf("%d%d", &n, &m); for (int i = 0; i < m; i++) { int x, y; scanf("%d%d", &x, &y); add(x,y); } tarjan(n); printf("Case %d: ", k); if (scc_cnt == 1) { printf("-1\n"); continue; } memset(rd, 0, sizeof(rd)); memset(cd, 0, sizeof(cd)); for (int u = 1; u <= n; u++) for (int i =head[u]; i !=-1; i=tu[i].next) { int v = tu[i].to; if (sccno[u] != sccno[v]) { rd[sccno[v]] += 1; cd[sccno[u]] += 1; } } int minn =1e9; for (int i = 1; i <= scc_cnt; i++) { int tmp = scc[i].size(); if (rd[i] == 0 || cd[i] == 0) minn = min(minn, tmp); } int x = minn, y = n - minn; LL ans = (LL)n*(LL)(n-1)- (LL)x * (LL)y - (LL)m; cout << ans << endl; } return 0; }