把所有scc找出来,缩点,然后在出度为0或入度为0的的块中选择点数最小的块作为独立块,使得这一块和其他的块不能强连通,其余的点都实现强连通即可!
#include <cstdio>
#include <vector>
#include <stack>
#include <cstring>
using namespace std;
const int N = 100010;
vector <int> G[N];
int pre[N], lowlink[N], sccno[N], num[N], dfs_clock, scc_cnt;
stack<int>S;
void dfs( int u )
{
pre[u] = lowlink[u] = ++dfs_clock;
S.push(u);
for ( int i = 0; i < G[u].size(); ++i ) {
int v = G[u][i];
if ( !pre[v] ) {
dfs( v ) ;
lowlink[u] = min( lowlink[u], lowlink[v] );
}
else if ( !sccno[v] ) lowlink[u] = min( pre[v], lowlink[u] );
}
if ( lowlink[u] == pre[u] ) {
scc_cnt++;
for (;;) {
int x = S.top(); S.pop();
sccno[x] = scc_cnt;
num[scc_cnt]++;
if ( x == u ) break;
}
}
}
void find_scc( int n )
{
dfs_clock = scc_cnt = 0;
memset( num, 0, sizeof(num));
memset( pre, 0, sizeof(pre));
memset( sccno, 0, sizeof(sccno));
for ( int i = 1; i <= n; ++i ) if ( !pre[i] ) dfs(i);
}
int T, n, m;
int in[N], out[N];
int main()
{
while ( scanf("%d", &T) != EOF ) {
int icase = 1;
while (T--) {
scanf("%d%d", &n, &m);
for ( int i = 0; i <= n; ++i ) G[i].clear();
int tmp = m, maxx = 0x3fffffff;
while ( tmp-- ) {
int a, b;
scanf("%d%d", &a, &b);
G[a].push_back(b);
}
find_scc( n );
//printf("%d\n", scc_cnt);
if ( scc_cnt == 1 ) {
printf("Case %d: -1\n", icase++);
continue;
}
memset( in, 0, sizeof(in));
memset( out, 0, sizeof(out));
for ( int i = 1; i <= n; ++i ) for ( int j = 0; j < G[i].size(); ++j ) {
int v = G[i][j];
if ( sccno[i] != sccno[v] ) out[sccno[i]]++, in[sccno[v]]++;
}
for ( int i = 1; i <= scc_cnt; ++i ) if ( num[i] < maxx && ( in[i] == 0 || out[i] == 0 )) maxx = num[i];
printf("Case %d: ", icase++ );
printf("%d\n", n*(n-1) - m - maxx*(n-maxx));
}
}
}