题意如上,含有重边(重边的话,俩个点就可以构成了边双连通)。

先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少。这里学习了树的直径求法:第一次选任意起点U,进行bfs,到达最远的一个点v(level最深)该点必然是树的直径的一个端点,,再从该点出发,bfs,到最深的一点,该点深度就是直径。(证明:先假设u,是直径上一点,S,T是直径的端点,设v!=t,则有(V,U)+(U,S)>(T,U)+(U,S),矛盾,故t=v;若u不是直径上一点,设u到直径上的一点为x,同理易证。

最后 缩点后树的边-直径即可。

再说说这次,哎,先是爆栈,没有在C++申请空间。。。 无向图的tarjian太不熟练了!很久没敲了。。。。

注意点:无向图求边双连通,缩点,可以这样:

法1:必需用前向星来保存边,然后标记访问边(同时标记反向边)的方法来处理。这样,重边的话,就在字自然在一个边通分量中了。(要求边数可以用数组存下),这样不用!=-father来判断。

法2,重边视为单边(只有俩个点不连通),不标记边,多一个参数father,在返祖边更新我的时候,加判断!=father。

  1. #pragma comment(linker, "/STACK:10240000000000,10240000000000") //申请空间
  2. #include<iostream>
  3. #include<vector>
  4. #include<cstring>
  5. #include<cstdio>
  6. #include<queue>
  7. #include<algorithm>
  8. #include<stack>
  9. using namespace std;
  10. const int maxv=300010;
  11. int dfn[maxv];int low[maxv];int visited[maxv];
  12. int ins[maxv];stack<int>sta;int scc[maxv];
  13. int times=0;int block=0;
  14. int n,m;
  15. int minn(int a,int b)
  16. {
  17. if(a<=b)return a;
  18. return b;
  19. }
  20. int nume=0;int e[2000500][2];int head[maxv];
  21. void inline adde(int i,int j) //原图
  22. {
  23. e[nume][0]=j;e[nume][1]=head[i];head[i]=nume++;
  24. e[nume][0]=i;e[nume][1]=head[j];head[j]=nume++;
  25. }
  26. int nume2=0;int newg[2000500][2];int head2[maxv];
  27. void inline adde2(int i,int j) //新图
  28. {
  29. newg[nume2][0]=j;newg[nume2][1]=head2[i];head2[i]=nume2++;
  30. newg[nume2][0]=i;newg[nume2][1]=head2[j];head2[j]=nume2++;
  31. }
  32. bool marke[2001000]; //标记边的访问
  33. void tarjan(int u)
  34. {
  35. dfn[u]=low[u]=++times;
  36. ins[u]=1;
  37. sta.push(u);
  38. for(int i=head[u];i!=-1;i=e[i][1])
  39. {
  40. int child=e[i][0];
  41. if(marke[i])continue; //注意放在这里,否则下面的会更新,起不了作用
  42. if(visited[child]==0)
  43. {
  44. visited[child]=1;
  45. marke[i]=marke[i^1]=1; //标记双向
  46. tarjan(child);
  47. low[u]=minn(low[u],low[child]);
  48. }
  49. else if(ins[child])
  50. {
  51. low[u]=minn(dfn[child],low[u]);
  52. }
  53. }
  54. if(low[u]==dfn[u]) //同一个边双连通
  55. {
  56. block++;
  57. int cur;
  58. do
  59. {
  60. cur=sta.top();
  61. ins[cur]=0;
  62. sta.pop();
  63. scc[cur]=block;
  64. }while(cur!=u);
  65. }
  66. }
  67. void rebuild()
  68. {
  69. for(int i=1;i<=n;i++) //遍历所有边,来重新建图,若在同一个边双连通中,则有边。
  70. {
  71. for(int j=head[i];j!=-1;j=e[j][1])
  72. {
  73. int ch=e[j][0];
  74. if(scc[i]!=scc[ch])
  75. adde2(scc[i],scc[ch]);
  76. }
  77. }
  78. }
  79. int lev[maxv];
  80. void bfsgetlev(int ss) //BFS分层
  81. {
  82. memset(lev,0,sizeof(lev));
  83. memset(visited,0,sizeof(visited));
  84. queue<int>q;
  85. q.push(ss);
  86. visited[ss]=1;
  87. while(!q.empty())
  88. {
  89. int cur=q.front();
  90. q.pop();
  91. for(int i=head2[cur];i!=-1;i=newg[i][1])
  92. {
  93. int vv=newg[i][0];
  94. if(!visited[vv])
  95. {
  96. lev[vv]=lev[cur]+1;
  97. q.push(vv);
  98. visited[vv]=1;
  99. }
  100. }
  101. }
  102. return ;
  103. }
  104. void init()
  105. {
  106.  
  107. block=times=0;nume=0;nume2=0;
  108. memset(marke,0,sizeof(marke));
  109. memset(dfn,0,sizeof(dfn));
  110. memset(low,0,sizeof(low));
  111. memset(visited,0,sizeof(visited));
  112. memset(head,-1,sizeof(head));
  113. memset(head2,-1,sizeof(head2));
  114.  
  115. }
  116. int main()
  117. {
  118. while(scanf("%d%d",&n,&m)!=EOF&&(n||m))
  119. {
  120. init();
  121. int a,b;
  122. for(int i=0;i<m;i++)
  123. {
  124. scanf("%d%d",&a,&b);
  125. adde(a,b);
  126. }
  127. visited[1]=1;
  128. tarjan(1);
  129. rebuild();
  130. int ans=0;
  131. bfsgetlev(1);
  132. int froms=0;
  133. int maxx=-1;
  134. for(int i=1;i<=block;i++)
  135. {
  136. if(lev[i]>maxx)
  137. {
  138. maxx=lev[i];
  139. froms=i;
  140. }
  141. }
  142. bfsgetlev(froms); //最远点(直直径的一个端点)
  143. for(int i=1;i<=block;i++)
  144. {
  145. if(lev[i]>maxx)
  146. {
  147. maxx=lev[i];
  148. }
  149. }
  150. ans=block-1-maxx;
  151. printf("%d\n",ans);
  152.  
  153. }
  154. return 0;
  155. }

hdu4612 无向图中任意添加一条边后使桥的数量最少 / 无向图缩点+求树的直径的更多相关文章

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

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

  2. python中pip添加国内镜像源后显著加速下载

    python中pip添加国内镜像源后显著加速下载 更换pip源到国内镜像,很多国外的库下载非常慢,添加国内镜像后安装下载速度提升非常明显(亲测有些可以由几十kb加速到几MB) pip国内的一些镜像阿里 ...

  3. HDU 4514 - 湫湫系列故事——设计风景线 - [并查集判无向图环][树形DP求树的直径]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4514 Time Limit: 6000/3000 MS (Java/Others) Memory Li ...

  4. HDU-4612 Warm up,tarjan求桥缩点再求树的直径!注意重边

    Warm up 虽然网上题解这么多,感觉写下来并不是跟别人竞争访问量的,而是证明自己从前努力过,以后回头复习参考! 题意:n个点由m条无向边连接,求加一条边后桥的最少数量. 思路:如标题,tarjan ...

  5. HDU4612+Tarjan缩点+BFS求树的直径

    tarjan+缩点+树的直径题意:给出n个点和m条边的图,存在重边,问加一条边以后,剩下的桥的数量最少为多少.先tarjan缩点,再在这棵树上求直径.加的边即是连接这条直径的两端. /* tarjan ...

  6. poj 3177 Redundant Paths【求最少添加多少条边可以使图变成双连通图】【缩点后求入度为1的点个数】

    Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11047   Accepted: 4725 ...

  7. 为什么不能在scrollview中直接添加一个image,然后使animation.begin()??

    http://stackoverflow.com/questions/17267451/animation-cant-begin-in-scrollview-in-windows-phone 以上是我 ...

  8. hdoj3534(树形dp,求树的直径的条数)

    题目链接:https://vjudge.net/problem/HDU-3534 题意:给出一棵树,求树上最长距离(直径),以及这样的距离的条数. 思路:如果只求直径,用两次dfs即可.但是现在要求最 ...

  9. HDU4612 Warm up 边双(重边)缩点+树的直径

    题意:一个连通无向图,问你增加一条边后,让原图桥边最少 分析:先边双缩点,因为连通,所以消环变树,每一个树边都是桥,现在让你增加一条边,让桥变少(即形成环) 所以我们选择一条树上最长的路径,连接两端, ...

随机推荐

  1. C05 C语言字符串和数组

    目录 数组 字符串 数组 概念 数组是有序数据的集合. 数组中的每一个元素属于同一个数据类型. 通过数组名和下标唯一确定数组中的元素. 一维数组的定义 语法格式 数据类型   数组名[常量表达式] 例 ...

  2. 10.字符串str的语法

    1).字符串的索引以及切片 s = 'ABCDLSESRF' #索引 s1 = s[0] print(s1) #A s2 = s[2] print(s2) #C s3 = s[-1] print(s3 ...

  3. jpeg和jpg的区别是什么

    JPG是JPEG的简写,jpg是后缀名,jpeg既可作为后缀名,又能代表文件格式:JPG——JPEG文件格式. 我们在系统自带的画图程序里保存文件,在保存类型:JPEG(*.JPG,*.JPEG,*. ...

  4. Broadcast BCM94322 用ubuntu修改ID

    1.按这个教程的6楼做的http://bbs.pcbeta.com/viewthread-1324168-1-1.html.注意我先下载 的是ubuntu9.05版本,做U盘启动进live 模式,43 ...

  5. Fortran学习记录3(选择语句)

    流程控制语句 if的基本用法 if-else语句块 多重判断if-elseif语句 if语句嵌套 Select case语句 Goto语句 PAUSE CONTINUE STOP 流程控制语句 if的 ...

  6. HDU - 4811 - Ball (思维)

    题意: 给出一定数量的三种颜色的球,计算如何摆放得到值最大(有一定顺序) 有三种摆放方法 1.如果放的是第一个(桌子上原来没有),数值不变 2.如果在末尾追加一个,那么增加前面不同颜色的个数的值 3. ...

  7. sscanf的使用

    sscanf的使用 语法 int ssanf(const char *buffer, const char *format,[argument]...); 参数 buffer 存储的数据 format ...

  8. 【搜索 技巧】Letter gaps

    需要一定技巧的搜索题 题目描述 记得做过这样一道题 Ponder This Challenge: In the string CABACB, each letter appears exactly t ...

  9. Linux三剑客之sed详解(2)

    一.sed 分组替换(),\1 实例:I am a oldboy teacher. 吧oldboy 提取出来 二.特殊符号&代表被替换的字符串 实例:批量替换文件名 把stu_102999_1 ...

  10. python爬虫(爬取图片)

    python爬虫爬图片 爬虫爬校花网校花的图片 第一步 载入爬虫模块 #载入爬虫模块 import re #载入爬虫模块 import requests #载入爬虫模块 第二步 获得校花网的地址,获得 ...