hdu4635:http://acm.hdu.edu.cn/showproblem.php?pid=4635
题意:给你一个有向图,然后问你最多可以加多少条边,是的原图不是一个强连通图。
题解:这一题确实不会,图论做的太少了,一下是一个人分析,觉得分析的很不错,代码也是看别人的。
首先强连通缩点,缩点之后,最终添加完边的图,肯定可以分成两个部X和Y,其中只有X到Y的边没有Y到X的边; *那么要使得边数尽可能的多,则X部肯定是一个完全图,Y部也是,同时X部中每个点到Y部的每个点都有一条边; *假设X部有x个点,Y部有y个点,则x+y=n; 同时边数F=x*y+x*(x-1)+y*(y-1),然后去掉已经有了的边m,则为答案; 当x+y为定值时,二者越接近,x*y越大,所以要使得边数最多,那么X部和Y部的点数的个数差距就要越大; 对于给定的有向图缩点,对于缩点后的每个点,如果它的出度或者入度为0,那么它才有可能成为X部或者Y部; 然后找出最大值即可;
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N=200010; 7 const int M=400010; 8 const int INF=0xffffffff; 9 struct Edge{ 10 int to,next; 11 } edge[M]; 12 13 int n,m,cnt,dep,top,atype; 14 int dfn[N],low[N],vis[N],head[N],st[N],belong[N],in[N],out[N],sum[N]; 15 //sum[i]记录第i个连通图的点的个数,in[i],out[i],表示缩点之后点的入度和初度。 16 void init(){ 17 cnt=dep=top=atype=0; 18 memset(head,-1,sizeof(head)); 19 memset(dfn,0,sizeof(dfn)); 20 memset(low,0,sizeof(low)); 21 memset(vis,0,sizeof(vis)); 22 memset(belong,0,sizeof(belong)); 23 memset(in,0,sizeof(in)); 24 memset(out,0,sizeof(out)); 25 memset(sum,0,sizeof(sum)); 26 } 27 void addedge(int u,int v){ 28 edge[cnt].to=v; 29 edge[cnt].next=head[u]; 30 head[u]=cnt++; 31 } 32 33 void Tarjan(int u){ 34 dfn[u]=low[u]=++dep; 35 st[top++]=u; 36 vis[u]=1; 37 for(int i=head[u]; i!=-1; i=edge[i].next){ 38 int v=edge[i].to; 39 if(!dfn[v]){ 40 Tarjan(v); 41 low[u]=min(low[u],low[v]); 42 } 43 else if(vis[v]){ 44 low[u]=min(low[u],dfn[v]); 45 } 46 } 47 int j; 48 if(dfn[u]==low[u]){ 49 atype++; 50 do{ 51 j=st[--top]; 52 belong[j]=atype; 53 sum[atype]++; //记录每个连通分量中点的个数 54 vis[j]=0; 55 } 56 while(u!=j); 57 } 58 } 59 60 long long solve(){ 61 if(n==1){ 62 return -1; 63 } 64 init(); 65 int u,v; 66 for(int i=0; i<m; i++){ 67 scanf("%d%d",&u,&v); 68 addedge(u,v); 69 } 70 for(int i=1; i<=n; i++) 71 if(!dfn[i]) 72 Tarjan(i); 73 if(atype==1){ 74 return -1; 75 } 76 for(int u=1; u<=n; u++) 77 for(int i=head[u]; i!=-1; i=edge[i].next){ 78 int v=edge[i].to; 79 if(belong[u]!=belong[v]){ 80 out[belong[u]]++; 81 in[belong[v]]++; 82 } 83 } 84 long long tmp=100000000; 85 for(int i=1; i<=atype; i++) 86 if(in[i]==0 || out[i]==0){ 87 tmp=min(tmp,(long long)sum[i]); 88 } 89 return tmp*(tmp-1)+(n-tmp)*(n-tmp-1)+tmp*(n-tmp)-m; 90 } 91 int cas; 92 int main(){ 93 scanf("%d",&cas); 94 int tt=1; 95 while(cas--){ 96 scanf("%d%d",&n,&m); 97 printf("Case %d: %I64d\n",tt++,solve()); 98 } 99 return 0; 100 }
Strongly connected
时间: 2024-11-05 18:52:52