题意:一个无向图,问建立一条新边以后桥的最小数量。

  分析:缩点以后,找出新图的树的直径,将这两点连接即可。

  但是题目有个note:两点之间可能有重边!而用普通的vector保存边的话,用v!=fa的话是没办法让重边访问的,因此,使用数组模拟邻接表的方法来储存边。

这样,只要访问了一条边以后,令E[i].vis=E[i^1].vis=1即可,这样可以防止无向图的边和重边搞混。原理就是按位异或,一个奇数^1变为比它小1的偶数,反之亦然:如5^1=4,4^1=5。

  具体见代码:

  1. #include <stdio.h>
  2. #include <algorithm>
  3. #include <string.h>
  4. #include <stack>
  5. #include <vector>
  6. #include <set>
  7. #include <queue>
  8. //#pragma comment(linker, "/STACK:1024000000,1024000000")
  9. using namespace std;
  10.  
  11. const int N = +;
  12.  
  13. int n,m,dfn[N],low[N];
  14. int head[N];
  15. int tot=;
  16. int dfs_clock;
  17. int bridge;
  18. int belong[N];
  19. int scc_cnt;
  20. int maxd;
  21. bool vis[N];
  22. vector<int> G[N];
  23. stack<int> S;
  24.  
  25. struct edge
  26. {
  27. int v;
  28. int vis;
  29. int nxt;
  30. }E[*+];
  31.  
  32. void addEdge(int u,int v)
  33. {
  34. E[tot].v=v;
  35. E[tot].vis=;
  36. E[tot].nxt=head[u];
  37. head[u]=tot++;
  38.  
  39. E[tot].v=u;
  40. E[tot].vis=;
  41. E[tot].nxt=head[v];
  42. head[v]=tot++;
  43. }
  44.  
  45. void tarjan(int u)
  46. {
  47. dfn[u]=low[u]=++dfs_clock;
  48. S.push(u);
  49. for(int i=head[u];i!=-;i=E[i].nxt)
  50. {
  51. int v = E[i].v;
  52. if(E[i].vis) continue;
  53. E[i].vis=E[i^].vis=;
  54.  
  55. if(!dfn[v])
  56. {
  57. tarjan(v);
  58. low[u]=min(low[u],low[v]);
  59.  
  60. if(low[v]>dfn[u]) bridge++;
  61. }
  62. else if(!belong[v])
  63. {
  64. low[u]=min(low[u],dfn[v]);
  65. }
  66. }
  67.  
  68. if(dfn[u]==low[u])
  69. {
  70. scc_cnt++;
  71. for(;;)
  72. {
  73. int x = S.top();S.pop();
  74. belong[x] = scc_cnt;
  75. if(x==u) break;
  76. }
  77. }
  78. }
  79.  
  80. void init()
  81. {
  82. memset(head,-,sizeof(head));
  83. tot=;
  84. memset(dfn,,sizeof(dfn));
  85. dfs_clock=;
  86. bridge=;
  87. memset(belong,,sizeof(belong));
  88. scc_cnt=;
  89. maxd=;
  90. for(int i=;i<=n;i++) G[i].clear();
  91. memset(vis,,sizeof(vis));
  92. }
  93.  
  94. //找到树的直径
  95. void findMaxDeep(int u,int deep)
  96. {
  97. vis[u]=;
  98.  
  99. maxd=max(maxd,deep);
  100. for(int i=;i<G[u].size();i++)
  101. {
  102. int v = G[u][i];
  103. if(!vis[v])
  104. {
  105. findMaxDeep(v,deep+);
  106. }
  107. }
  108. }
  109.  
  110. //用bfs来找到一个叶子节点
  111. int findRoot()
  112. {
  113. queue<int> Q;
  114. Q.push();
  115. vis[]=;
  116. int last=;
  117. while(!Q.empty())
  118. {
  119. int x = Q.front();Q.pop();
  120. for(int i=;i<G[x].size();i++)
  121. {
  122. int v = G[x][i];
  123. if(!vis[v])
  124. {
  125. Q.push(v);
  126. vis[v]=;
  127. last=v;
  128. }
  129. }
  130. }
  131. return last;
  132. }
  133.  
  134. void solve()
  135. {
  136. for(int i=;i<=n;i++) if(!dfn[i]) tarjan(i);
  137.  
  138. //重新建图
  139. for(int i=;i<=n;i++)
  140. {
  141. for(int j=head[i];j!=-;j=E[j].nxt)
  142. {
  143. int v = E[j].v;
  144. int x = belong[i];
  145. int y = belong[v];
  146. if(x!=y)
  147. {
  148. G[x].push_back(y);
  149. G[y].push_back(x);
  150. }
  151. }
  152. }
  153.  
  154. int root=findRoot();
  155. memset(vis,,sizeof(vis));
  156.  
  157. findMaxDeep(root,);
  158.  
  159. printf("%d\n",bridge-maxd);
  160. }
  161.  
  162. int main()
  163. {
  164. while(scanf("%d%d",&n,&m)==)
  165. {
  166. if(n== && m==) break;
  167. init();
  168.  
  169. for(int i=;i<=m;i++)
  170. {
  171. int u,v;
  172. scanf("%d%d",&u,&v);
  173. addEdge(u,v);
  174. }
  175.  
  176. solve();
  177. }
  178. }

  但是奇怪的是,重新建图以后找叶子节点的时候,这里用G[x].size()==2不能够实现。讲道理,原理上是没错的,尽管后来发现如果缩点后只有一个点的话是个例外,但是即使排除了这个特殊情况仍然不行,,,这个问题也留着以后探讨吧。。

HDU 4612 Warm up —— (缩点 + 求树的直径)的更多相关文章

  1. 4612 warm up tarjan+bfs求树的直径(重边的强连通通分量)忘了写了,今天总结想起来了。

    问加一条边,最少可以剩下几个桥. 先双连通分量缩点,形成一颗树,然后求树的直径,就是减少的桥. 本题要处理重边的情况. 如果本来就两条重边,不能算是桥. 还会爆栈,只能C++交,手动加栈了 别人都是用 ...

  2. F - Warm up - hdu 4612(缩点+求树的直径)

    题意:有一个无向连通图,现在问添加一条边后最少还有几个桥 分析:先把图缩点,然后重构图为一棵树,求出来树的直径即可,不过注意会有重边,构树的时候注意一下 *********************** ...

  3. HDU 4612 Warm up(双连通分量缩点+求树的直径)

    思路:强连通分量缩点,建立一颗新的树,然后求树的最长直径,然后加上一条边能够去掉的桥数,就是直径的长度. 树的直径长度的求法:两次bfs可以求,第一次随便找一个点u,然后进行bfs搜到的最后一个点v, ...

  4. hdu4612 无向图中随意加入一条边后使桥的数量最少 / 无向图缩点+求树的直径

    题意如上,含有重边(重边的话,俩个点就能够构成了边双连通). 先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少.这里学习了树的直径求法:第一次选随意起点U,进行bfs,到达最远的一个点v ...

  5. hdu4612 无向图中任意添加一条边后使桥的数量最少 / 无向图缩点+求树的直径

    题意如上,含有重边(重边的话,俩个点就可以构成了边双连通). 先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少.这里学习了树的直径求法:第一次选任意起点U,进行bfs,到达最远的一个点v ...

  6. (求树的直径)Warm up -- HDU -- 4612

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612 给一个无向图, 加上一条边后,求桥至少有几个: 那我们加的那条边的两个顶点u,v:一定是u,v之 ...

  7. hdoj 4612 Warm up【双连通分量求桥&&缩点建新图求树的直径】

    Warm up Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Su ...

  8. HDU 4612 Warm up (边双连通分量+缩点+树的直径)

    <题目链接> 题目大意:给出一个连通图,问你在这个连通图上加一条边,使该连通图的桥的数量最小,输出最少的桥的数量. 解题分析: 首先,通过Tarjan缩点,将该图缩成一颗树,树上的每个节点 ...

  9. HDU 4612——Warm up——————【边双连通分量、树的直径】

    Warm up Time Limit:5000MS     Memory Limit:65535KB     64bit IO Format:%I64d & %I64u Submit Stat ...

随机推荐

  1. windows下安装mongoDB(zip版)

    windows下安装mongoDB(zip版) 下面说明如何在win10下用zip包安装好mongoDB数据库 首先要先从网上下载mongoDB的zip包 http://dl.mongodb.org/ ...

  2. 【原创】编程基础之Jekins

    Jenkins 2.164.2 官方:https://jenkins.io 一 简介 Build great things at any scale The leading open source a ...

  3. Django rest-framework框架-认证组件的简单实例

    第一版 : 自己写函数实现用户认证 #models from django.db import models #用户表 class UserInfo(models.Model): user_type_ ...

  4. mysql 添加grant权限

    GRANT USAGE ON *.* TO 'xxxx'@'x.%.%.%' WITH GRANT OPTION;

  5. HTML 5浏览器端数据库

    HTML 5浏览器端数据库为什么要使用浏览器端数据库:随着浏览器处理能力的增强,越来越多的双喜鸟网站开始考虑在客户端存储大量的数据,这可以减少用户从服务器获取数据的等待时间. 1.本地存储-本地存储可 ...

  6. WinPE基础知识之导出表

    // 导出的东西包括函数(变量.类)地址,序号,函数(变量.类)名 typedef struct _IMAGE_EXPORT_DIRECTORY { DWORD Characteristics; // ...

  7. 本地套接字-本地socket

    本地套接字简单应用场景 一 #服务端--简单 import socket import os a='sock_file' if os.path.exists(a): os.remove(a) s=so ...

  8. java lambda 所有列求和

    今天做东西的时候遇到一个需求,求list集合所有列的求和.折腾半天也没有搞出来,网上大部分都是单列求和就像下面这样的,其他都差多,什么 min,max avg count 只得到了number这个属性 ...

  9. Linux搭建.net core CI/CD环境

    一.简介 微服务开发中自动化.持续化工程十分重要,在成熟的CI/CD环境中项目团队可以灵活分配,大大提供团队效率.如果还不了解什么是CI/CD,可以先查看相关文章,这里主要介绍环境的搭建,相关原理就不 ...

  10. PAT Basic 1064 朋友数 (20 分)

    如果两个整数各位数字的和是一样的,则被称为是“朋友数”,而那个公共的和就是它们的“朋友证号”.例如 123 和 51 就是朋友数,因为 1+2+3 = 5+1 = 6,而 6 就是它们的朋友证号.给定 ...