HDU - 4635 Strongly connected
Strongly connected HDU - 4635
题意:给你一个n个点m条边的有向简单图,问最多加多少边使得图还是一个简单图,并且整个图不是一个强连通,如果原先整个图就是个强连通,就输出-1。
首先要知道的是简单图,没有重边,而且没有自环,但是有其他的环。这样先不考虑整个图最终不是一个强连通,我们最多就可以加n*(n-1)-m,也是每个点向其他点连一条边,然后减去原来已经有的。
然后我们来考虑让整个图不是强连通,我们先把其他子强连通求出来这样缩点之后就是一棵树了。那我们原先要让它变成一个强连通的话,就是入度为零和出度为零的点互相连边,然后多出来的可以任意向其他点连边,
那现在不让它是强连通,并且要能加最多的边的话,我们就剩下一个入度为0或者出度为0的点不连即可。这样不连的边就是这个点向其他点连的边,也就是这个强连通里的点数*剩下的点数,所以我们需要统计下每个点(强连通)的大小,
这样就是找所有入度或者出度为0的点 大小*(n-大小)最小的那一个,然后减去便可。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 typedef long long ll; 5 const int N=1e5+11; 6 struct Side{ 7 int v,ne; 8 }S[N]; 9 bool ins[N]; 10 int n,m,sn,dn,head[N],dfn[N],low[N]; 11 int cn,tn,col[N],sta[N],size[N],in[N],out[N]; 12 void init(){ 13 sn=dn=cn=tn=0; 14 for(int i=0;i<=n;i++){ 15 head[i]=-1; 16 dfn[i]=0; 17 ins[i]=false; 18 } 19 } 20 void add(int u,int v){ 21 S[sn].v=v; 22 S[sn].ne=head[u]; 23 head[u]=sn++; 24 } 25 void tarjan(int u){ 26 dfn[u]=low[u]=++dn; 27 ins[u]=true; 28 sta[++tn]=u; 29 for(int i=head[u],v;~i;i=S[i].ne){ 30 v=S[i].v; 31 if(!dfn[v]){ 32 tarjan(v); 33 low[u]=min(low[u],low[v]); 34 }else if(ins[v]) low[u]=min(low[u],dfn[v]); 35 } 36 if(dfn[u]==low[u]){ 37 col[u]=++cn; 38 size[cn]=1; 39 ins[u]=false; 40 while(sta[tn]!=u){ 41 col[sta[tn]]=cn; 42 size[cn]++; 43 ins[sta[tn--]]=false; 44 } 45 tn--; 46 } 47 } 48 ll solve(){ 49 for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); 50 if(cn==1) return -1; 51 ll ans=1ll*n*(n-1)-m,mins=1e18+9; 52 for(int i=1;i<=cn;i++) in[i]=out[i]=0; 53 for(int i=1,ci,cj;i<=n;i++){ 54 ci=col[i]; 55 for(int j=head[i];~j;j=S[j].ne){ 56 cj=col[S[j].v]; 57 if(ci!=cj){ 58 in[cj]++; 59 out[ci]++; 60 } 61 } 62 } 63 for(int i=1;i<=cn;i++) 64 if(!in[i]||!out[i]) mins=min(mins,1ll*size[i]*(n-size[i])); 65 return ans-mins; 66 } 67 int main() { 68 int t=1,T,u,v; 69 scanf("%d",&T); 70 while(t<=T){ 71 scanf("%d%d",&n,&m); 72 init(); 73 for(int i=0;i<m;i++){ 74 scanf("%d%d",&u,&v); 75 add(u,v); 76 } 77 printf("Case %d: %lld\n",t++,solve()); 78 } 79 return 0; 80 }
我太难了~给个三连吧,亲~~~