求在原有向图上最多可以添加多少边,使其仍满足不是强连通图
思路:缩点后分成两部分,保证两部分不强连通(两部分之间,其中一部分的入度或出度应为0),
思路:缩点后分成两部分,保证两部分不强连通(两部分之间,其中一部分的入度或出度应为0),
然后用sum(所有边)-tot(已有边)-两部分点数的乘积。
/*求在原有向图上最多可以添加多少边,使其仍满足不是强连通图
思路:缩点后分成两部分,保证两部分不强连通(两部分之间,其中一部分的入度或出度应为0),
然后用sum(所有边)-tot(已有边)-两部分点数的乘积
*/
#include <iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
#define N 100005
#define maxn 100005
int f[N],ans[N];
struct Edge
{
int to,next;
}edge[maxn];
int head[N],tot;
int low[N],dfn[N],Stack[N],belong[N];
int inl[N],outl[N];
int index,top,scc;
bool instack[N];
long long int num[N];
void addedge(int u,int v)
{
edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++;
}
void Tarjan(int u)//tarjan有向图缩点
{
int v;
low[u]=dfn[u]=++index;
Stack[top++]=u;
instack[u]=true;
for(int i=head[u];i!=-1;i=edge[i].next){
v=edge[i].to;
if(!dfn[v])
{
Tarjan(v);
if(low[u]>low[v]) low[u]=low[v];
}
else if(instack[v] && low[u]>dfn[v])
low[u]=dfn[v];
}
if(low[u]==dfn[u]){
scc++;
do{
v=Stack[--top];
instack[v]=false;
belong[v]=scc;//
num[scc]++;
}while(v!=u);
}
}
void solve(int n)
{
memset(dfn,0,sizeof(dfn));
memset(instack,false,sizeof(instack));
//memset(belong,0,sizeof(belong));
memset(num,0,sizeof(num));
index=scc=top=0;
for(int i=1;i<=n;i++)
if(!dfn[i]) Tarjan(i);
}
void init(){
tot=0;
memset(head,-1,sizeof(head));
memset(inl,0,sizeof(inl));
memset(outl,0,sizeof(outl));
}
int main()
{
int T;
int n,m,x,y;
cin>>T;
for(int t=1;t<=T;t++)
{
init();
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d",&x,&y);
addedge(x,y);
}
solve(n);
if(scc==1) printf("Case %d: %d\n",t,-1);
else{
//sort(num+1,num+scc+1);
long long int sum=n*(n-1)-tot;
long long int ans=0;
long long int res=0;
for(int i=1;i<=n;i++)
for(int j=head[i];j!=-1;j=edge[j].next)
{
if(belong[i]!=belong[edge[j].to]) {
outl[belong[i]]++;
inl[belong[edge[j].to]]++;
}
}
for(int i=scc;i>=1;i--)
ans+=num[i];
for(int i=1;i<=scc;i++)
{
if(inl[i]&&outl[i]) continue;
res=max(res,sum-(ans-num[i])*num[i]);
}
printf("Case %d: %I64d\n",t,res);
}
}
return 0;
}