Gym - 100712H Bridges(边—双连通分量)
Posted 谦谦君子,陌上其华
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gym - 100712H Bridges(边—双连通分量)相关的知识,希望对你有一定的参考价值。
https://vjudge.net/problem/Gym-100712H
题意:
给出一个图,求添加一条边后最少的桥数量。
思路:
参考了ZSQ大神的题解http://blog.csdn.net/v5zsq/article/details/61922051
很明显的边—双连通的题目,首先缩点建新图。然后寻找树中的最大直径,这样就能将桥的数量减至最小。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<queue> 7 #include<cmath> 8 #include<map> 9 #include<stack> 10 using namespace std; 11 12 const int maxn=100000+5; 13 14 struct Edge 15 { 16 int to,next; 17 bool flag;//标记是否是桥 18 }edge[maxn*2]; 19 20 stack<int> S; 21 int n,m; 22 int head[maxn],tot; 23 int low[maxn],dfn[maxn],belong[maxn]; 24 int index,top; 25 int block;//边双连通块数 26 bool instack[maxn]; 27 int bridge;//桥的数目 28 int e[maxn][2]; 29 int deep; //最长直径 30 int pos; //最长直径端点 31 32 void addedge(int u,int v) 33 { 34 edge[tot].to=v,edge[tot].next=head[u],edge[tot].flag=0; 35 head[u]=tot++; 36 } 37 38 void Tarjan(int u,int pre) 39 { 40 int v; 41 low[u]=dfn[u]=++index; 42 S.push(u); 43 instack[u]=1; 44 for(int i=head[u];~i;i=edge[i].next) 45 { 46 v=edge[i].to; 47 if(v==pre)continue; 48 if(!dfn[v]) 49 { 50 Tarjan(v,u); 51 if(low[u]>low[v])low[u]=low[v]; 52 if(low[v]>dfn[u]) 53 { 54 bridge++; 55 edge[i].flag=1; 56 edge[i^1].flag=1; 57 } 58 } 59 else if(instack[v]&&low[u]>dfn[v]) 60 low[u]=dfn[v]; 61 } 62 if(low[u]==dfn[u]) 63 { 64 block++; 65 do 66 { 67 v=S.top(); S.pop(); 68 instack[v]=0; 69 belong[v]=block; 70 } 71 while(v!=u); 72 } 73 } 74 75 void init() 76 { 77 memset(dfn,0,sizeof(dfn)); 78 index=block=top=bridge=tot=0; 79 memset(head,-1,sizeof(head)); 80 } 81 82 //邻接表寻找树的直径 83 void dfs(int u,int fa,int cnt) 84 { 85 if(cnt>deep) {deep=cnt;pos=u;} 86 for(int i=head[u];~i;i=edge[i].next) 87 { 88 int v=edge[i].to; 89 if(v!=fa) dfs(v,u,cnt+1); 90 } 91 } 92 93 int main() 94 { 95 //freopen("D:\\input.txt","r",stdin); 96 int T; 97 scanf("%d",&T); 98 while(T--) 99 { 100 scanf("%d%d",&n,&m); 101 init(); 102 for(int i=1;i<=m;i++) 103 { 104 scanf("%d%d",&e[i][0],&e[i][1]); 105 addedge(e[i][0],e[i][1]); 106 addedge(e[i][1],e[i][0]); 107 } 108 Tarjan(1,1); 109 110 //缩点,重建图 111 tot=0; 112 memset(head,-1,sizeof(head)); 113 int ans=0; 114 for(int i=1;i<=m;i++) 115 { 116 int u=belong[e[i][0]], v=belong[e[i][1]]; 117 if(u!=v) 118 { 119 ans++; 120 addedge(u,v); 121 addedge(v,u); 122 } 123 } 124 125 deep=0; 126 dfs(1,1,0); 127 deep=0; 128 dfs(pos,pos,0); 129 printf("%d\n",ans-deep); 130 } 131 return 0; 132 }
以上是关于Gym - 100712H Bridges(边—双连通分量)的主要内容,如果未能解决你的问题,请参考以下文章
[HDU4738]Caocao's Bridges(求割边最小权值)