http://acm.hdu.edu.cn/showproblem.php?pid=4635
强连通分量缩点之后+简单计算,具体见代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100100;
struct Edge {
int v , next;
Edge () {}
Edge (int v , int next) : v(v) , next(next) {};
}edge[maxn<<1];
int E , head[maxn];
int n , m;
void init() {
E = 0; memset(head,-1,sizeof(int) * (n+1));
}
void addedge(int u,int v) {
edge[E] = Edge(v , head[u]); head[u] = E++;
}
int idx , cnt ;
int dfn[maxn] , low[maxn] , id[maxn];
int sta[maxn] , top;
bool ins[maxn];
void tarjan(int u) {
dfn[u] = low[u] = ++ cnt;
sta[++top] = u;
ins[u] = true;
int v;
for(int i=head[u];i!=-1;i=edge[i].next) {
v = edge[i].v;
if(!dfn[v]) {
tarjan(v); low[u] = min(low[u] , low[v]);
}
else if(ins[v]) low[u] = min(low[u] , dfn[v]);
}
if(low[u] == dfn[u]) {
idx ++;
do {
v = sta[top--];
ins[v] = false;
id[v] = idx;
}while(u != v);
}
}
void solve() {
idx = cnt = top = 0;
memset(ins , false , sizeof(int) * (n+1));
memset(dfn , 0 ,sizeof(int) * (n+1));
for(int i=1;i<=n;i++) {
if(!dfn[i]) tarjan(i);
}
}
int ccc[maxn];
bool bb[maxn] , cc[maxn];
int main() {
int T;
scanf("%d" , &T);
int cas = 1;
while(T--) {
scanf("%d%d",&n,&m);
printf("Case %d: " , cas ++);
int mm = m;
init(); int u , v;
while(m--) {
scanf("%d%d",&u,&v);
addedge(u , v);
}
solve();
//printf("check idx is %d
" , idx);
if(idx == 1) {
printf("-1
");
continue;
}
for(int i=1;i<=idx;i++) ccc[i] = 0;
for(int i=1;i<=n;i++) ccc[ id[i] ] ++;
for(int i=1;i<=idx;i++) bb[i] = cc[i] = false;
for(int u=1;u<=n;u++) {
for(int i=head[u];i!=-1;i=edge[i].next) {
int v = edge[i].v;
if(id[u] != id[v]) bb[ id[u] ] = cc[ id[v] ] = true;
}
}
long long ans = 0;
for(int i=1;i<=idx;i++) {
if(bb[i] && cc[i]) continue;
long long n1 = ccc[i] , n2 = n - n1;
long long tt = n1 * (n1 - 1) + n2 * (n2 - 1) + n1 * n2;
if(tt > ans) ans = tt;
}
ans -= mm;
//printf("%lld
" , ans);
cout << ans << endl;
}
return 0;
}