大意:给定一个无向连通图,判断至少加多少的边,才能使任意两点之间至少有两条的独立的路(没有公共的边,但可以经过同一个中间的顶点)。
思路:在同一个双连通分量里的所有的点可以看做一个点,收缩后,新图是一棵树,树的边便是原图的桥。现在问题转化为“在树中至少添加多少条边能使图变成边双连通图”,即添加的边的个数=(树中度为一的节点数目+1)/2,用trajan算法求双联通分量
这是一个模板
1 #include<iostream>
2 #include<cstdio>
3 #include<string.h>
4 #include<algorithm>
5 #include<queue>
6 #include<vector>
7 using namespace std;
8 const int maxn=1e4+10;
9 struct node
10 {
11 int v,cut,nxt;
12 }G[2*maxn];
13 int cnt;
14 int head[maxn];
15 int Stack[maxn];
16 int instack[maxn];
17 int low[maxn],dfn[maxn];
18 int belong[maxn],du[maxn];
19 int block,index;
20 int bridge,top;
21 void init()
22 {
23 cnt=0;
24 memset(head,-1,sizeof(head));
25 }
26 void build(int u,int v)
27 {
28 G[cnt].v=v;G[cnt].nxt=head[u];G[cnt].cut=0;head[u]=cnt++;
29 }
30 void tarjan(int u,int pre)
31 {
32 low[u]=dfn[u]=++index;
33 Stack[top++]=u;
34 instack[u]=1;
35 int v;
36 for(int i=head[u];i!=-1;i=G[i].nxt){
37 v=G[i].v;
38 if(pre==v) continue;
39 if(!dfn[v]){
40 tarjan(v,u);
41 low[u]=min(low[u],low[v]);
42 if(low[v]>dfn[u]){
43 bridge++;
44 G[i].cut=1;
45 G[i^1].cut=1;
46 }
47 }
48 else if(low[u]>dfn[v]&&instack[v]) low[u]=dfn[v];
49 }
50 if(low[u]==dfn[u]){
51 block++;
52 do{
53 v=Stack[--top];
54 instack[v]=0;
55 belong[v]=block;
56 }while(v!=u);
57 }
58 }
59 void solve(int n)
60 {
61 int i,j;
62 int index=0;
63 bridge=0;
64 top=0;
65 block=0;
66 memset(low,0,sizeof(low));
67 memset(dfn,0,sizeof(dfn));
68 memset(belong,0,sizeof(belong));
69 memset(instack,0,sizeof(instack));
70 tarjan(1,0);
71 for(i=1;i<=n;i++){
72 for(j=1;j!=-1;j=G[j].nxt){
73 if(G[j].cut)
74 du[belong[i]]++;
75 }
76 }
77 int ans=0;
78 for(i=1;i<=block;i++){
79 if(du[i]==1)
80 ans++;
81 }
82 printf("%d\n",(ans+1)/2);
83 }
84 int main()
85 {
86 int n,m;
87 while(~scanf("%d%d",&n,&m)){
88 init();
89 for(int i=0;i<m;i++){
90 int u,v;
91 scanf("%d%d",&u,&v);
92 build(u,v);
93 build(v,u);
94 }
95 solve(n);
96 }
97 return 0;
98 }