首先跑一遍tarjan 缩点无异议 缩完点后 若scc_cnt = 1 那么直接输出 -1 对于多个点的连通图来说 首先缩了点的那个点 里面的点是随便 连的 sum += sz[i] * (sz[i] - 1) 最后减去已连的就好了
再其次就是 缩完点之后的图 是树 因为树 是单向边 所以我们可以把 已经按照那个方向 那个点全都 连上 其次就是还有反向边 反向边一定要剩下至少一个点没有连反向边 并且是叶子节点 这样我们就能完全选完了
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
const int N = 2e5 + 10,M = 1e6 + 10;
typedef long long ll;
int n,m;
int head[N],to[M * 2],last[M * 2],cnt;
void add(int a,int b){
to[++cnt] = b;
last[cnt] = head[a];
head[a] = cnt;
}
int chu[N],ru[N];
int dfn[N],low[N],times,bridge[N],sum,scc_cnt;
int belong[N],flag[N],sta[N],top,sz[N];
void tarjan(int x){
dfn[x] = low[x] = ++times;
sta[++top] = x,flag[x] = 1;
for(int i = head[x]; i != -1; i = last[i]){
int j = to[i];
if(!dfn[j]){
tarjan(j);
low[x] = min(low[x],low[j]);
if(dfn[x] < low[j]){
bridge[j] = 1;
sum++;
}
}else if(flag[j]){
low[x] = min(low[x],dfn[j]);
}
}
if(dfn[x] == low[x]){
++scc_cnt;
int y;
do{
y = sta[top--];
belong[y] = scc_cnt;
sz[scc_cnt]++;
flag[y] = 0;
}while(y != x);
}
}
vector<int>v;
int main(){
int n,m;
int t;
cin >> t;
for(int _ = 1; _ <= t; _++){
cin >>n>> m;
v.clear();
memset(head,-1,sizeof head);
memset(dfn,0,sizeof dfn);
memset(sz,0,sizeof sz);
memset(chu,0,sizeof chu);
memset(ru,0,sizeof ru);
top = 0,times = 0,scc_cnt = 0;
cnt = 1;
sum = 0;
for(int i = 1; i <= m; i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i = 1; i <= n; i++){
if(!dfn[i]){
tarjan(i);
}
}
printf("Case %d: ",_);
if(scc_cnt == 1){
printf("-1\n");
continue;
}
ll sum = 0;
for(int i = 1; i <= scc_cnt; i++){
sum += 1ll * sz[i] * (n - sz[i]);
}
sum /= 2;
sum -= m;
for(int i = 1; i <= scc_cnt; i++){
sum += 1ll * sz[i] * (sz[i] - 1);
}
for(int i = 1; i <= n; i++){
for(int j = head[i]; j != -1; j = last[j]){
int k = to[j];
if(belong[i] != belong[k]){
chu[belong[i]]++;
ru[belong[k]]++;
}
}
}
int minn = 0x3f3f3f3f,is;
for(int i = 1; i <= scc_cnt; i++){
if(ru[i] == 0 || chu[i] == 0){
if(minn > sz[i]){
minn = sz[i];
is = i;
}
}
}
ll maxn = 0;
for(int i = 1; i <= scc_cnt; i++){
if(i == is) continue;
maxn += 1ll * (n - sz[i] - minn) * sz[i];
}
cout << sum + maxn / 2 <<endl;
}
return 0;
}