Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 437 Accepted Submission(s): 193
最终添加完边的图,肯定可以分成两个部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,(然后去掉已经有了的边m,就是答案),当x+y为定值时,二者越接近,x*y越大,所以要使得边数最多,那么X部和Y部的点数的个数差距就要越大,所以首先对于给定的有向图缩点,对于缩点后的每个点,如果它的出度或者入度为0,那么它才有可能成为X部或者Y部,所以只要求缩点之后的出度或者入度为0的点中,包含节点数最少的那个点,令它为一个部,其它所有点加起来做另一个部,就可以得到最多边数的图了
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int VM=200010; const int EM=200010; const int INF=0x3f3f3f3f; struct Edge{ int to,nxt; }edge[EM<<1]; long long n,m,cnt,head[VM]; long long dep,top,atype; long long dfn[VM],low[VM],vis[VM],stack[VM],belong[VM],indeg[VM],outdeg[VM],sum[VM]; void addedge(int cu,int cv){ edge[cnt].to=cv; edge[cnt].nxt=head[cu]; head[cu]=cnt++; } void Tarjan(int u){ dfn[u]=low[u]=++dep; stack[top++]=u; vis[u]=1; for(int i=head[u];i!=-1;i=edge[i].nxt){ int 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]); } } int j; if(dfn[u]==low[u]){ atype++; do{ j=stack[--top]; belong[j]=atype; sum[atype]++; //记录每个连通分量中点的个数 //printf(" sum[%lld]=%lld\n",atype,sum[atype]); vis[j]=0; }while(u!=j); } } void init(){ cnt=0; memset(head,-1,sizeof(head)); dep=0, top=0, atype=0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(vis,0,sizeof(vis)); memset(belong,0,sizeof(belong)); memset(indeg,0,sizeof(indeg)); memset(outdeg,0,sizeof(outdeg)); memset(sum,0,sizeof(sum)); } int main(){ //freopen("input.txt","r",stdin); int t,cases=0; scanf("%d",&t); while(t--){ cin>>n>>m; if(n==1){ printf("Case %d: -1\n",++cases); continue; } init(); int u,v; for(int i=0;i<m;i++){ scanf("%d%d",&u,&v); addedge(u,v); } for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i); if(atype==1){ printf("Case %d: -1\n",++cases); continue; } for(int u=1;u<=n;u++) for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(belong[u]!=belong[v]){ outdeg[belong[u]]++; indeg[belong[v]]++; } } long long ans=0,tmp; for(long long i=1;i<=atype;i++) if(indeg[i]==0 || outdeg[i]==0){ //找出度或者入度为0的点,包含节点数最少的那个点 //令它为一个部,其它所有点加起来做另一个部,就可以得到最多边数的图了 tmp=sum[i]; ans=max(ans,tmp*(tmp-1)+(n-tmp)*(n-tmp-1)+tmp*(n-tmp)-m); } cout<<"Case "<<(++cases)<<": "<<ans<<endl; } return 0; }