HDOJ4612双连通分量缩点+找树的直径
Posted MekakuCityActor
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDOJ4612双连通分量缩点+找树的直径相关的知识,希望对你有一定的参考价值。
http://acm.hdu.edu.cn/showproblem.php?pid=4612
Warm up
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 8309 Accepted Submission(s): 1905
Problem Description
N planets are connected by M bidirectional channels that allow instant transportation. It‘s always possible to travel between any two planets through these channels.
If we can isolate some planets from others by breaking only one channel , the channel is called a bridge of the transportation system.
People don‘t like to be isolated. So they ask what‘s the minimal number of bridges they can have if they decide to build a new channel.
Note that there could be more than one channel between two planets.
If we can isolate some planets from others by breaking only one channel , the channel is called a bridge of the transportation system.
People don‘t like to be isolated. So they ask what‘s the minimal number of bridges they can have if they decide to build a new channel.
Note that there could be more than one channel between two planets.
Input
The input contains multiple cases.
Each case starts with two positive integers N and M , indicating the number of planets and the number of channels.
(2<=N<=200000, 1<=M<=1000000)
Next M lines each contains two positive integers A and B, indicating a channel between planet A and B in the system. Planets are numbered by 1..N.
A line with two integers ‘0‘ terminates the input.
Each case starts with two positive integers N and M , indicating the number of planets and the number of channels.
(2<=N<=200000, 1<=M<=1000000)
Next M lines each contains two positive integers A and B, indicating a channel between planet A and B in the system. Planets are numbered by 1..N.
A line with two integers ‘0‘ terminates the input.
Output
For each case, output the minimal number of bridges after building a new channel in a line.
Sample Input
4 4
1 2
1 3
1 4
2 3
0 0
Sample Output
0
题目大意:给一个连通图,求加一条边之后最少还有多少个桥。
题目分析:首先看到要求是"改造桥",则先进行缩点,由于是改造桥,所以进行边双连通的缩点,然后求树的直径【树上桥最多的一条路】,则最后结果ans=原来桥数-直径。
【说坑点】:
【1】
无向图的缩点与有向图不一样,有向图如果一条边的两端点不在一个连通分量里面则加一条边即可,也就是可以使用原来的结构体数组【因为是最多一换一】
而无向图中,一条边两端点不在同一个连通分量里面则需要加入两条边【即会出现一换二的情况,则就不能直接放进原本的结构体数组了,否则会覆盖原数组数据】【WA..】
【2】
无向图的边数组的存储大小应该是 2 * MAXN 而不是 MAXN...【无限RE 】
【3】
对桥什么的判断一定要用 low[ v ] > dfn[ u ] ,而不能用 low[ v ] > low[ u ]因为low[ u ]是一直随孩子变化的,而只有和 dfn[ u ]这个用于不变的变量比较才能得到正确的位置关系。
【无限wa...】
1 #include <stdio.h> 2 #include <iostream> 3 #include <algorithm> 4 #include <string.h> 5 #include <queue> 6 #include <vector> 7 using namespace std; 8 9 const int MAXN = 200010; 10 const int MAXM = 1000015; 11 struct Edge 12 { 13 int to,from,next; 14 }edge[MAXM*2],eedge[MAXM*2]; 15 int head[MAXN],edge_cnt; 16 int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];//Belong数组的值是1~block 17 int Index,top; 18 int block; 19 bool Instack[MAXN]; 20 int bridge; 21 int n,m; 22 int key,d,vis[MAXN]; 23 void addedge(int u,int v) 24 { 25 edge[edge_cnt].from=u; 26 edge[edge_cnt].to = v;edge[edge_cnt].next = head[u]; 27 head[u] = edge_cnt++; 28 } 29 void addedge2(int u,int v) 30 { 31 eedge[edge_cnt].from=u; 32 eedge[edge_cnt].to = v;eedge[edge_cnt].next = head[u]; 33 head[u] = edge_cnt++; 34 } 35 void Tarjan(int u,int id) 36 { 37 int v; 38 Low[u] = DFN[u] = ++Index; 39 Stack[top++] = u; 40 Instack[u] = true; 41 for(int i = head[u];i != -1;i = edge[i].next) 42 { 43 v = edge[i].to; 44 if( i == (id^1))continue; 45 if( !DFN[v] ) 46 { 47 Tarjan(v,i); 48 if(Low[u] > Low[v])Low[u] = Low[v]; 49 if(Low[v] > DFN[u]) 50 { 51 bridge++; 52 } 53 } 54 else if(Instack[v] && Low[u] > DFN[v]) 55 Low[u] = DFN[v]; 56 } 57 if(Low[u] == DFN[u]) 58 { 59 block++; 60 do 61 { 62 v = Stack[--top]; 63 Instack[v] = false; 64 Belong[v] = block; 65 } 66 while( v != u ); 67 } 68 } 69 void dfs(int u,int len) 70 { 71 vis[u]=1; 72 if(len > d) 73 { 74 d=len; 75 key=u; 76 } 77 for(int i = head[u]; i != -1 ; i=eedge[i].next) 78 { 79 int v=eedge[i].to; 80 if(!vis[v]) 81 { 82 dfs(v,len+1); 83 } 84 } 85 return; 86 } 87 void init() 88 { 89 edge_cnt=0; 90 memset(head,-1,sizeof(head)); 91 } 92 void solve() 93 { 94 memset(DFN,0,sizeof(DFN)); 95 memset(Low,0,sizeof(Low)); 96 memset(Belong,0,sizeof(Belong)); 97 memset(Instack,false,sizeof(Instack)); 98 Index = top = block = bridge = 0; 99 Tarjan(1,-1); 100 int orz=edge_cnt; 101 edge_cnt=0; 102 memset(head,-1,sizeof(head)); 103 for(int i = 0 ; i < orz ; i++) 104 { 105 if(Belong[edge[i].to]!=Belong[edge[i].from]) 106 { 107 108 addedge2(Belong[edge[i].to],Belong[edge[i].from]); 109 addedge2(Belong[edge[i].from],Belong[edge[i].to]); 110 } 111 } 112 d=0; key=0; 113 memset(vis,0,sizeof(vis)); 114 dfs(1,0); 115 d=0;// cout << key <<endl; 116 memset(vis,0,sizeof(vis)); 117 dfs(key,0); 118 119 cout << bridge-d<<endl; 120 } 121 int main() 122 { 123 scanf("%d%d",&n,&m); 124 while(n||m) 125 { 126 init(); 127 int M=m; 128 while(M--) 129 { 130 int u,v; 131 scanf("%d%d",&u,&v); 132 addedge(u,v); 133 addedge(v,u); 134 } 135 solve(); 136 scanf("%d%d",&n,&m); 137 } 138 return 0; 139 }
以上是关于HDOJ4612双连通分量缩点+找树的直径的主要内容,如果未能解决你的问题,请参考以下文章
HDU 4612 Warm up(双连通分量缩点+求树的直径)
Warm up HDU - 4612( 树的直径 边双连通分量)