做完后,看了解题报告,思路是一样的。我就直接粘过来吧
最终添加完边的图,肯定可以分成两个部X和Y,其中只有X到Y的边没有Y到X的边,那么要使得边数尽可能的多,则X部肯定是一个完全图,Y部也是,同时X部中每个点到Y部的每个点都有一条边,假设X部有x个点,Y部有y个点,有x+y=n,同时边数F=x*y+x*(x-1)+y*(y-1),整理得:F=N*N-N-x*y,当x+y为定值时,二者越接近,x*y越大,所以要使得边数最多,那么X部和Y部的点数的个数差距就要越大,所以首先对于给定的有向图缩点,对于缩点后的每个点,如果它的出度或者入度为0,那么它才有可能成为X部或者Y部,所以只要求缩点之后的出度或者入度为0的点中,包含节点数最少的那个点,令它为一个部,其它所有点加起来做另一个部,就可以得到最多边数的图了
//109MS 2916KB #include <stdio.h> #include <string.h> #define LL long long const int M = 100005; const int inf = 0x3f3f3f3f; struct Edge { int to,nxt; } edge[M]; int head[M],low[M],dfn[M],stack[M+10]; int vis[M],out[M],in[M],belong[M]; int scc,cnt ,top,ep; LL n,m; int min (int a,int b) { return a > b ? b : a; } void addedge (int cu,int cv) { edge[ep].to = cv; edge[ep].nxt = head[cu]; head[cu] = ep ++; } void Tarjan(int u) { int v; dfn[u] = low[u] = ++cnt; stack[top++] = u; vis[u] = 1; for (int i = head[u]; i != -1; i = edge[i].nxt) { v = edge[i].to; if (!dfn[v]) { Tarjan(v); low[u] = min(low[u],low[v]); } else if (vis[v]) low[u] = min(low[u],dfn[v]); } if (dfn[u] == low[u]) { ++scc; do { v = stack[--top]; vis[v] = 0; belong[v] = scc; } while (u != v); } } void solve() { int u,v; scc = top = cnt = 0; memset (vis,0,sizeof(vis)); memset (dfn,0,sizeof(dfn)); memset (out,0,sizeof(out)); memset (in,0,sizeof(in)); for (u = 1; u <= n; u ++) if (!dfn[u]) Tarjan(u); for (u = 1; u <= n; u ++) { for (int i = head[u]; i != -1; i =edge[i].nxt) { v = edge[i].to; if (belong[u] != belong[v]) { out[belong[u]] ++; in[belong[v]] ++; } } } int num[M],Min; memset (num,0,sizeof(num)); for (u = 1; u <= n; u ++) if (!in[belong[u]]) num[belong[u]] ++; for (u = 1; u <= scc; u ++) if (num[u]!= 0&&num[u]<Min) Min = num[u]; memset (num,0,sizeof(num)); for (u = 1; u <= n; u ++) if (!out[belong[u]]) num[belong[u]] ++; for (u = 1; u <= scc; u ++) if (num[u]!= 0&&num[u]<Min) Min = num[u]; if (scc == 1) { printf ("-1\n"); return ; } LL ans = n*(n-1)-Min*(n-Min) - m; printf ("%I64d\n",ans); } int main () { #ifdef LOCAL freopen("in.txt","r",stdin); #endif int T,u,v,cnt = 0; scanf ("%d",&T); while (T --) { scanf ("%I64d%I64d",&n,&m); ep = 0; memset (head,-1,sizeof(head)); for (int i = 0; i < m; i++) { scanf ("%d%d",&u,&v); addedge(u,v); } printf ("Case %d: ",++cnt); solve(); } return 0; }