/* hdu 4635 Strongly connected 强连通 题意:给一个简单(无重边,无自环:就是自己直接指向自己的边)有向图, 若是强连通的,就输出-1 否则输出可以最多加多少条边还是非强连通的; 加完边的状态就是,有两个强连通块儿(包含的点数分别是n,m),各自内部任意两点之间都有两条不同方向的边, 两个块儿之间只有单方向的边,另一个方向的边是因为保持非强连通牺牲掉的(数量是n*m), n个点的强连通图最多可以有n*(n-1)条边,有m条已存在,n*m条被牺牲了,不可建,剩下的就是可见的, 对没有入度或没有出度的块儿枚举,使得n*m最小即可 */ #include<stdio.h> #include<stack> using namespace std; const int N=100000+10; stack<int>s; int ret; struct node { int v,next; } e[N]; int ins[N],fang[N],head[N],low[N],belong[N]; int ru[N],chu[N]; int numd[N]; int n,m,yong; void tarjan(int k) { int j,u; fang[k]=low[k]=yong++; ins[k]=1; s.push(k);//强连通为什么要用栈?栈中其往上的都是可能和他是同一连通分量的,不可以访问非栈上节点是他们不可能在同一连通分量上(访问过而不在栈上,还可能是同一连通分量么),若访问 访问过而不在栈上 的节点(不是同一连通分量,他们早已出栈,说明他们的根还是比较高的,对他没有更新) for(j=head[k];j;j=e[j].next) { u=e[j].v; if(fang[u]==0) { tarjan(u); if(low[u]<low[k]) low[k]=low[u]; }else if(ins[u]&&fang[u]<low[k])//u可能在上一路上已被访问过,或者u就是k的祖先,他们一定是同一连通分量;与双连通不同的是:他要求的是自己不越过自己,所以,即使他有回边,早晚更新都是一样;双连通担心的是他提前更新,导致他的孩子也提前更新,从而fang[本节点]>low[孩子]=low[本节点]=low[本节点的父节点] low[k]=fang[u]; } if(low[k]==fang[k])//其能探到的最低的不越过他自己,说明其以下是一个连通分量 { ret++; do{ j=s.top(); s.pop(); ins[j]=0; belong[j]=ret; }while(j!=k); } } void adde(int a,int b) { e[yong].v=b; e[yong].next=head[a]; head[a]=yong++; } int main() { int t,ti,a,b,i,j; scanf("%d",&t); for(ti=1;ti<=t;++ti) { ret=0; yong=1; scanf("%d%d",&n,&m); memset(head,0,sizeof(head)); for(i=0;i<m;++i) { scanf("%d%d",&a,&b); adde(a,b); } yong=1; memset(ins,0,sizeof(ins)); memset(fang,0,sizeof(fang)); for(i=1;i<=n;i++) { if(fang[i]==0) { tarjan(i); } } if(ret==1) { printf("Case %d: -1\n",ti); continue; } memset(chu,0,sizeof(chu)); memset(ru,0,sizeof(ru)); memset(numd,0,sizeof(numd)); for(i=1;i<=n;i++) { numd[belong[i]]++; int index=head[i]; for(;index;index=e[index].next) { j=e[index].v; if(belong[i]!=belong[j]) { chu[belong[i]]++; ru[belong[j]]++; } } } __int64 sheng=1; sheng=sheng*n*(n-1); sheng=sheng-m; __int64 xiao=0x7fffffffffffff; __int64 tem; for(i=1;i<=ret;++i) { if(chu[i]==0||ru[i]==0) { tem=((__int64)numd[i])*(n-numd[i]); if(tem<xiao) { xiao=tem; } } } sheng=sheng-xiao; printf("Case %d: %I64d\n",ti,sheng); } return 0; }