如果有孤立的点,则把其他的点连成完全图。然后从该点向每一个点连一条有向边。总共(n-1)*(n-1) 条。
如果没有孤立的点,尽量找点数最小的强连通,且这个强连通只有向外的有向边,或者只有向里的有向边。把这些点练成完全图。其他的点也连成完全图。最后从这些点,分别向其他的点连有向边。设两个完全图的点数为n,m则总边数为n*(n-1)+m*(m-1);从一个完全图,指向另一个完全图的边数(n*m);
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <string>
#define LL long long
#define DB double
#define SF scanf
#define SI(a) scanf("%d",&a)
#define SD(a) scanf("%lf",&a)
#define PF printf
#define MM(a,b) memset(a,b,sizeof(a))
#define N 100009
#define bug cout<<"bug"<<endl
using namespace std;
int n,m;
int dfn[N],low[N],ind,col[N],color;
bool post[N];
stack<int> S;
vector<int>L[N];
void tarjan(int k){
dfn[k] = low[k] =ind++;
post[k] = true;
S.push(k);
for(int i=0;i<(int)L[k].size();i++){
int to = L[k][i];
if(!dfn[to]){
tarjan(to);
low[k] = min(low[k],low[to]);
}else if(post[to]&&low[k]>dfn[to]){
low[k] = dfn[to];
}
}
if(dfn[k]==low[k]){
color++;int i;
for(i=S.top(),S.pop();i!=k;i=S.top(),S.pop())
{
col[i] = color; post[i] = false;
}
col[i]=color,post[i] = false;
}
}
struct LLL{
int l,r;
} link[N];
int in[N],ou[N];
int num[N];
LL solve()
{
for(int i=1;i<=n;i++)
if(dfn[i]==0)
tarjan(i);
// for(int i=1;i<=n;i++) cout<<col[i]<<" ";cout<<endl;
if(color==1) return -1;
memset(in,0,sizeof(in));
memset(ou,0,sizeof(ou));
for(int i=0;i<m;i++)
{
if(col[link[i].l]==col[link[i].r])continue;
ou[col[link[i].l]]++;
in[col[link[i].r]]++;
}
memset(num,0,sizeof(num));
for(int i=1;i<=n;i++)
num[col[i]]++;
LL ans = -1;
for(int i=1;i<=color;i++)
{
if(in[i]==0||ou[i]==0)
{
int a = num[i],b = n-num[i];
if(a==1||b==1)
return 1ll*(n-1)*(n-1)-m;
ans = max(1ll*a*(a-1)+1ll*b*(b-1)+1ll*a*b-m,ans);
}
}return ans;
}
int main()
{
int T=1,cas;SF("%d",&cas);
while(cas--)
{
SF("%d%d",&n,&m);
memset(dfn,0,sizeof(dfn));
ind = 1;color = 0;
for(int i=0;i<=n;i++) L[i].clear();
int a,b;
for(int i=0;i<m;i++)
{
SF("%d%d",&a,&b);
link[i].l = a;
link[i].r = b;
L[a].push_back(b);
}
cout<<"Case "<<T<<": "<<solve()<<endl;
T++;
}
return 0;
}