一.基本概念

1.桥:若无向连通图的边割集中只有一条边,则称这条边为割边或者桥 (离散书上给出的定义。。

通俗的来说就是无向连通图中的某条边,删除后得到的新图联通分支至少为2(即不连通;

2.割点:若无向连通图的点割集中只有一个点,则称这个点为割点或者关节点 ;

通俗的来说就是无向连通图中的某条边,删除后得到的新图连通分支至少为2;

二:tarjan算法求割点和桥

1.割点:1)当前节点为树根的时候,条件是“要有多余一棵子树”;

         如果这有一颗子树,去掉这个点也没有影响,如果有两颗子树,去掉这点,两颗子树就不连通了;

2)当前节点u不是树根的时候,条件是“low[v]>=dfn[u]”,也就是在u之后遍历的点,能够向上翻,

      最多到u,如果能翻到u的上方,那就有环了,去掉u之后,图仍然连通。

2.桥:若一条无向边(u,v)是桥,

1)当且仅当无向边(u,v)是树枝边,需要满足dfn(u)<low(v),即v向上翻不到u及其以上的点,

      那么u--v之间一定能够有1条或者多条边不能删去, 因为他们之间有部分无环,是桥,

      如果v能上翻到u那么u--v就是一个环,删除其中一条路径后,仍然是连通的。

3.注意点:1)求桥的时候:因为边是无方向的,所以父亲孩子节点的关系需要自己规定一下,

在tarjan的过程中if(v不是u的父节点) low[u]=min(low[u],dfn[v]);

因为如果v是u的父亲,那么这条无向边就被误认为是环了。

2)找桥的时候:注意看看有没有重边,有重边的边一定不是桥,也要避免误判。

4.也可以先进行tarjan(),求出每一个点的dfn和low,并记录dfs过程中的每个点的父节点,

    遍历所有点的low,dfn来寻找桥和割点

代码:

  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <vector>
  4. #include <string.h>
  5. using namespace std;
  6.  
  7. const int MAXN=1e5+;
  8. vector<int> mp[MAXN];
  9. bool is_cut[MAXN];
  10. int n, m, count=;
  11. int low[MAXN], dfn[MAXN], pre[MAXN];//pre[u]记录u的父亲节点编号
  12. //dfn[u]记录节点u在DFS过程中被遍历到的次序号,low[u]记录节点u或u的子树通过非父子边追溯到最早的祖先节点(即DFS次序号最小
  13.  
  14. void tarjan(int u, int fu){
  15. pre[u]=fu;//记录当前u的父亲节点
  16. dfn[u]=low[u]=count++;
  17. for(int i=; i<mp[u].size(); i++){
  18. int v=mp[u][i];
  19. if(dfn[v]==-){
  20. tarjan(v, u);
  21. low[u]=min(low[u], low[v]);
  22. }else if(fu!=v){//如果v是u的父亲的话,即有重边,那么不可能是桥
  23. low[u]=min(low[u], dfn[v]);
  24. }
  25. }
  26. }
  27.  
  28. void solve(void){
  29. int rootson=;
  30. tarjan(, );
  31. for(int i=; i<=n; i++){
  32. int v=pre[i];
  33. if(v==){
  34. rootson++;//统计根节点的子树个数,若其不小于2,即为割点
  35. }else if(low[i]>=dfn[v]){
  36. is_cut[v]=true;
  37. }
  38. }
  39. if(rootson>) is_cut[]=true;
  40. puts("割点为:");
  41. for(int i=; i<=n; i++){//输出割点
  42. if(is_cut[i]){
  43. printf("%d ", i);
  44. }
  45. }
  46. puts("\n桥为:");
  47. for(int i=; i<=n; i++){
  48. int v=pre[i];
  49. if(v>&&low[i]>dfn[v]){
  50. printf("%d %d\n", v, i);
  51. }
  52. }
  53. puts("");
  54. }
  55.  
  56. int main(void){
  57. scanf("%d%d", &n, &m);
  58. for(int i=; i<m; i++){
  59. int x, y;
  60. scanf("%d%d", &x, &y);
  61. mp[x].push_back(y);
  62. mp[y].push_back(x);
  63. }
  64. memset(dfn, -, sizeof(dfn));
  65. memset(low, -, sizeof(low));
  66. solve();
  67. return ;
  68. }

求桥的另一种写法(更快一点):

  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <string.h>
  4. using namespace std;
  5.  
  6. const int MAXN = 1e5 + ;
  7.  
  8. struct node{
  9. int v, next, use;
  10. }edge[MAXN << ];
  11.  
  12. bool bridge[MAXN];
  13. int low[MAXN], dfn[MAXN], vis[MAXN];
  14. int head[MAXN], pre[MAXN], ip, sol, count;
  15.  
  16. void init(void){
  17. memset(head, -, sizeof(head));
  18. memset(vis, false, sizeof(vis));
  19. memset(bridge, false, sizeof(bridge));
  20. count = sol = ip = ;
  21. }
  22.  
  23. void addedge(int u, int v){
  24. edge[ip].v = v;
  25. edge[ip].use = ;
  26. edge[ip].next = head[u];
  27. head[u] = ip++;
  28. }
  29.  
  30. void tarjan(int u){
  31. vis[u] = ;
  32. dfn[u] = low[u] = count++;
  33. for(int i = head[u]; i != -; i = edge[i].next){
  34. if(!edge[i].use){
  35. edge[i].use = edge[i ^ ].use = ;
  36. int v = edge[i].v;
  37. if(!vis[v]){
  38. pre[v] = u;
  39. tarjan(v);
  40. low[u] = min(low[u], low[v]);
  41. if(dfn[u] < low[v]){
  42. sol++;
  43. bridge[v] = true;
  44. }
  45. }else if(vis[v] == ){
  46. low[u] = min(low[u], dfn[v]);
  47. }
  48. }
  49. }
  50. vis[u] = ;
  51. }
  52.  
  53. int main(void){
  54. int n, m, q, x, y, cas = ;
  55. while(~scanf("%d%d", &n, &m)){
  56. if(!n && !m) break;
  57. init();
  58. for(int i = ; i < m; i++){
  59. scanf("%d%d", &x, &y);
  60. addedge(x, y);
  61. addedge(y, x);
  62. }
  63. pre[] = ;
  64. tarjan();
  65. for(int i = ; i <= n; i++){
  66. if(bridge[i]) cout << i << " " << pre[i] << endl;
  67. }
  68. }
  69. return ;
  70. }

以上参考博客:http://www.cnblogs.com/c1299401227/p/5402747.html

求无向图的割点和桥模板(tarjan)的更多相关文章

  1. 求 无向图的割点和桥,Tarjan模板

    /* 求 无向图的割点和桥 可以找出割点和桥,求删掉每个点后增加的连通块. 需要注意重边的处理,可以先用矩阵存,再转邻接表,或者进行判重 */ const int MAXN = 10010; cons ...

  2. tarjan算法--求无向图的割点和桥

    一.基本概念 1.桥:是存在于无向图中的这样的一条边,如果去掉这一条边,那么整张无向图会分为两部分,这样的一条边称为桥无向连通图中,如果删除某边后,图变成不连通,则称该边为桥. 2.割点:无向连通图中 ...

  3. Tarjan无向图的割点和桥(割边)全网详解&算法笔记&通俗易懂

    更好的阅读体验&惊喜&原文链接 感谢@yxc的腿部挂件 大佬,指出本文不够严谨的地方,万分感谢! Tarjan无向图的割点和桥(割边) 导言 在掌握这个算法前,咱们有几个先决条件. [ ...

  4. 无向图的割点和桥 tarjan 模板

    #include <bits/stdc++.h> using namespace std; const int MAXN = 20005; const int MAXM = 100005; ...

  5. tarjan算法--求解无向图的割点和桥

    1.桥:是存在于无向图中的这样的一条边,如果去掉这一条边,那么整张无向图会分为两部分,这样的一条边称为桥 也就是说 无向连通图中,如果删除某边后,图变成不连通,则称该边为桥 2.割点:无向连通图中,如 ...

  6. 【关节点+桥】关节点和桥模板 Tarjan

    #include <cstdio> #include <cstring> #include <algorithm> using namespace std; con ...

  7. Tarjan求无向图割点、桥详解

    tarjan算法--求无向图的割点和桥   一.基本概念 1.桥:是存在于无向图中的这样的一条边,如果去掉这一条边,那么整张无向图会分为两部分,这样的一条边称为桥无向连通图中,如果删除某边后,图变成不 ...

  8. [Tarjan系列] Tarjan算法求无向图的双连通分量

    这篇介绍如何用Tarjan算法求Double Connected Component,即双连通分量. 双联通分量包括点双连通分量v-DCC和边连通分量e-DCC. 若一张无向连通图不存在割点,则称它为 ...

  9. [Tarjan系列] Tarjan算法求无向图的桥和割点

    RobertTarjan真的是一个传说级的大人物. 他发明的LCT,SplayTree这些数据结构真的给我带来了诸多便利,各种动态图论题都可以用LCT解决. 而且,Tarjan并不只发明了LCT,他对 ...

随机推荐

  1. 实现单击列表头对ListView的动态排序

    排序是根据列的类型来的,就ID列来说,int类型的排序结果是3,5,17,而如果你把该列类型改为string,结果就会是17,3,5,如果你定义列的时候不加类型,默认是string,如果是自定义类型, ...

  2. 简单label控件 自制

    using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using ...

  3. 九度OJ 1141:Financial Management (财务管理) (平均数)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:939 解决:489 题目描述: Larry graduated this year and finally has a job. He's ...

  4. ALTER USER USER() IDENTIFIED BY 'password';

    [root@test mysql]# bin/mysqld 2018-08-04T14:09:33.831318Z 0 [Warning] [MY-011070] [Server] 'Disablin ...

  5. mysql 5.6 bug

    https://dev.mysql.com/doc/refman/5.6/en/account-management-sql.html USE mysql; SELECT Host,User FROM ...

  6. 建立FTP服务器(FTP服务器名要与创建的用户名一致)

    1新建用户 2. 3.建立FTP

  7. Objective-C 学习笔记

    1. Hello, World #import <Foundation/Foundation.h> int main() {    /* my first program in Objec ...

  8. uboot之logo显示【转】

    本文转载自:http://blog.csdn.net/tuwenqi2013/article/details/60583735 版权声明:本文为博主原创文章,博主欢迎各位转载. 一.logo的调用流程 ...

  9. js正则表达式,密码长度要大于6位,由数字和字母组成

    var pwd = $("#pwd").val(); var reg = /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,}$/; if(!reg ...

  10. SQL server 备份/恢复/压缩 进度查询

    第一步,用 sp_who2 查出备份的sid(或在窗口中的连接属性中看) exec sp_who2 第二步,用以下查询获得运行情况(看 percent_complete列) SELECT sessio ...