题意:
一个有向图,如果是强连通就输出-1,如果不是,你可以不停加边,求使其依然不是强连通图的最多可加的边数。不能有重边或自环。
题解:
最优解形成的图一定是个完全图删边成有且只有一个点只有入边或出边,即边数为n*(n-1)-(n-1)。
但是可能图里含有强连通分量,所以tarjan缩点后,要在所有只有入边或出边的点里选一个点作为上述的特殊点。注意由于缩过点,比如当前点由t个点缩成,所以新图边数为n*(n-1)-t*(n-t),减去m就是解。
//Time:109ms
//Memory:5700KB
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <vector>
#define MAXN 300010
#define MOD 10007
#define INF 1000000007
using namespace std;
bool insta[MAXN];
int sta[MAXN],stop,now,n;
int in[MAXN],out[MAXN];
int dfn[MAXN],low[MAXN],cnt[MAXN],bel[MAXN],btop;
int he[MAXN],nex[MAXN],to[MAXN],top;
void add(int u,int v)
{
to[top]=v;
nex[top]=he[u];
he[u]=top++;
}
void tarjan(int h)
{
dfn[h]=low[h]=now++;
sta[stop++]=h;
insta[h]=1;
for(int i=he[h];i!=-1;i=nex[i])
if(dfn[to[i]]==0)
{
tarjan(to[i]);
low[h]=min(low[h],low[to[i]]);
}
else if (insta[to[i]]) low[h]=min(low[h],dfn[to[i]]);
if(low[h]==dfn[h])
{
int tmp=0;
do
{
insta[sta[--stop]]=0;
bel[sta[stop]]=btop;
++tmp;
}while(sta[stop]!=h);
cnt[btop++]=tmp;
}
}
int main()
{
//freopen("/home/moor/Code/input","r",stdin);
int ncase,m;
long long ans;
scanf("%d",&ncase);
for(int h=1;h<=ncase;++h)
{
scanf("%d%d",&n,&m);
memset(he,-1,sizeof(he));
memset(dfn,0,sizeof(dfn));
memset(insta,0,sizeof(insta));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
now=1;
top=0;
stop=0;
btop=0;
for(int i=0;i<m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
}
ans=0;
for(int i=1;i<=n;++i)
if(!dfn[i])
tarjan(i);
printf("Case %d: ",h);
if(btop==1) printf("-1\n");
else
{
long long tmp=(long long)n*(n-1);
for(int i=1;i<=n;++i)
for(int j=he[i];j!=-1;j=nex[j])
if(bel[to[j]]!=bel[i])
++in[bel[to[j]]],++out[bel[i]];
for(int i=0;i<btop;++i)
if(in[i]==0||out[i]==0)
ans=max(ans,tmp-(n-cnt[i])*cnt[i]);
cout<<ans-m<<'\n';
}
}
return 0;
}