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(边—双连通分量)的主要内容,如果未能解决你的问题,请参考以下文章

Gym - 100712H

*BZOJ2095: [Poi2010]Bridges

[HDU4738]Caocao's Bridges(求割边最小权值)

BZOJ2095[Poi2010]Bridges 动态加边网络流

「POI2010」Bridges

[BZOJ2095]Bridges