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\n" , idx); if(idx == 1) { printf("-1\n"); 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\n" , ans); cout << ans << endl; } return 0; }