割点的定义:

  感性理解,所谓割点就是在无向连通图中去掉这个点和所有和这个点有关的边之后,原先连通的块就会相互分离变成至少两个分离的连通块的点。

   举个例子: 图中的4号点就是割点,因为去掉4号点和有关边之后连通块{1,2,3} {5} {6}就相互分离了。

图片来自:一篇写的较好的blog:https://www.cnblogs.com/jason2003/p/7603886.html

  

Tarjan算法求割点:

  有好多个Tarjan算法,不要傻傻分不清~~

  其实和有向图求强连通分量的Tarjan算法差不多啦,也用到了dfn和low。

  因为是无向连通图,所以横向边是没有意义的,(有反向边的存在)。

  dfn[u]:u在搜索树中被遍历到的次序号(时间戳)。

  low[u]:u或u的子树中的结点经过最多一条后向边能追溯到的最早的树中结点的次序号(dfn),有点懵,先不管他,感性理解就是通过边到达的点的最小时间戳。

割点判断条件:

  ①:若u为树的树根,那么只要u有两个及以上的子节点,那么只要u点消失,子节点所在的连通块就会分离了。

如果只有一个子节点,那么u消失之后还剩下那个子节点的连通块,仍是一个并不是多个。

  ②:若u不为树根,v不为u的父结点,当dfn[u]<=low[v]时,u就为割点,由该式子的含义可得,v以及v的子树最多只能到达u结点,

不能到达u的祖先,此时删掉u,那么(v及v的子树)和(u的祖先)就会相互分离了,自然u就是割点。

  求割点时若(u,v)为后向边,v不为u的父结点,low[u]=min{low[u],dfn[v]},里面一定要写dfn[v],不能写low[v]。

原因详见:https://www.luogu.org/blog/ztyluogucpp/solution-p3388

割点模板:

  L3388 【模板】割点(割顶):https://www.luogu.org/problemnew/show/P3388

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define INF 0x3f3f3f3f
  4. #define ll long long
  5. #define maxn 100009
  6. inline ll read()
  7. {
  8. ll x=,f=;char ch=getchar();
  9. while(ch<''||ch>''){if(ch=='-') f=-;ch=getchar();}
  10. while(ch>=''&&ch<=''){x=(x<<)+(x<<)+(ll)(ch-'');ch=getchar();}
  11. return x*f;
  12. }
  13. int head[maxn],dfn[maxn],low[maxn],point[maxn];
  14. int n,m,k,ans,cnt,id,tot,root;
  15. struct edge
  16. {
  17. int to,nxt;
  18. }p[maxn<<];
  19.  
  20. void add(int x,int y)
  21. {
  22. ++cnt,p[cnt].to=y,p[cnt].nxt=head[x],head[x]=cnt;
  23. }
  24.  
  25. void Tarjan(int u,int fa)
  26. {
  27. dfn[u]=low[u]=++id;
  28. int child=;
  29. for(int i=head[u];i;i=p[i].nxt)
  30. {
  31. int v=p[i].to;
  32. if(!dfn[v])
  33. {
  34. Tarjan(v,u);
  35. low[u]=min(low[u],low[v]);
  36. if(u!=root&&low[v]>=dfn[u])
  37. point[u]=;
  38. if(u==root&&++child>=)
  39. point[u]=;
  40. }
  41. else
  42. low[u]=min(low[u],dfn[v]);
  43. }
  44.  
  45. }
  46. int main()
  47. {
  48. // freopen(".in","r",stdin);
  49. // freopen(".out","w",stdout);
  50. n=read(),m=read();
  51. for(int i=;i<=m;i++)
  52. {
  53. int x=read(),y=read();
  54. add(x,y),add(y,x);
  55. }
  56. for(int i=;i<=n;i++)
  57. if(!dfn[i])
  58. root=i,Tarjan(i,i);
  59. for(int i=;i<=n;i++)
  60. if(point[i])
  61. tot++;
  62. printf("%d\n",tot);
  63. for(int i=;i<=n;i++)
  64. if(point[i])
  65. printf("%d ",i);
  66. fclose(stdin);
  67. fclose(stdout);
  68. return ;
  69. }

割边的定义:

  和割点的定义类似,只不过是把去掉点以及与点有关的边改成了去掉这条边看是否连通就行啦。

Tarjan算法求割边:

  和求割点只有一点点小区别...

   因为有可能存在重边的问题,所以要将一条无向边拆为两条编号一样的有向边,用邻接表进行储存,在判断(u,v)是否为后向边的时候要注意判断是树枝边的反向边还是新的一条边。

割边判断条件:

  dfn[u]<low[v],不可以取等号,因为取等号意味着v及v的子树能够到达结点u,那么(u,v)这条边自然就不是割边了。

  

割边模板:

  L1656 炸铁路:https://www.luogu.org/problemnew/show/P1656

  裸的割边模板,虽然不需要判断重边但是还是加上比较好,再用优先队列维护一下答案就可以了。

  判断是否是树枝边的反向边的时候只需要判断vis[i^1]是否等于1就行了,因为是这样判断的,所以在建边的时候cnt必须从1开始,因为0^1=0,并不会得到1这条反向边。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define re register int
  4. #define ll long long
  5. #define INF 0x3f3f3f3f
  6. #define maxn 159
  7. #define maxm 5009
  8. inline ll read()
  9. {
  10. ll x=,f=;char ch=getchar();
  11. while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
  12. while(ch>=''&&ch<=''){x=(x<<)+(x<<)+(ll)(ch-'');ch=getchar();}
  13. return x*f;
  14. }
  15. priority_queue<pair<int,int> >q;
  16. int head[maxn],dfn[maxn],low[maxn];
  17. bool vis[maxm<<];
  18. int n,m,k,ans,tot,id,cnt=;
  19. struct edge
  20. {
  21. int to,nxt;
  22. }p[maxm<<];
  23.  
  24. void add(int x,int y)
  25. {
  26. p[++cnt]={y,head[x]},head[x]=cnt;
  27. }
  28.  
  29. void Tarjan(int u)
  30. {
  31. dfn[u]=low[u]=++id;
  32. for(int i=head[u];i;i=p[i].nxt)
  33. {
  34. if(vis[i^])
  35. continue;
  36. int v=p[i].to;
  37. vis[i]=;
  38. if(!dfn[v])
  39. {
  40. Tarjan(v);
  41. low[u]=min(low[u],low[v]);
  42. if(dfn[u]<low[v])
  43. q.push(make_pair(-min(u,v),-max(u,v)));
  44. }
  45. else
  46. low[u]=min(low[u],dfn[v]);
  47. }
  48. }
  49. int main()
  50. {
  51. // freopen(".in","r",stdin);
  52. // freopen(".out","w",stdout);
  53. n=read(),m=read();
  54. for(int i=;i<=m;i++)
  55. {
  56. int x=read(),y=read();
  57. add(x,y),add(y,x);
  58. }
  59. for(int i=;i<=n;i++)
  60. if(!dfn[i])
  61. Tarjan(i);
  62. while(q.size())
  63. {
  64. printf("%d %d\n",-q.top().first,-q.top().second);
  65. q.pop();
  66. }
  67. fclose(stdin);
  68. fclose(stdout);
  69. return ;
  70. }

    

  

Tarjan求割点(割顶) 割边(桥)的更多相关文章

  1. 洛谷P3388 【模板】割点(割顶)(tarjan求割点)

    题目背景 割点 题目描述 给出一个n个点,m条边的无向图,求图的割点. 输入输出格式 输入格式: 第一行输入n,m 下面m行每行输入x,y表示x到y有一条边 输出格式: 第一行输出割点个数 第二行按照 ...

  2. Tarjan求割点和桥

    by szTom 前置知识 邻接表存储及遍历图 tarjan求强连通分量 割点 割点的定义 在一个无向图中,如果有一个顶点集合,删除这个顶点集合以及这个集合中所有顶点相关联的边以后,图的连通分量增多, ...

  3. tarjan求割点与割边

    tarjan求割点与割边 洛谷P3388 [模板]割点(割顶) 割点 解题思路: 求割点和割点数量模版,对于(u,v)如果low[v]>=dfn[u]那么u为割点,特判根结点,若根结点子树有超过 ...

  4. $割点割顶tarjan$

    原题 #include <bits/stdc++.h> using namespace std; typedef long long LL; inline LL read () { LL ...

  5. tarjan求割点割边的思考

    这个文章的思路是按照这里来的.这里讨论的都是无向图.应该有向图也差不多. 1.如何求割点 首先来看求割点.割点必须满足去掉其以后,图被分割.tarjan算法考虑了两个: 根节点如果有两颗及以上子树,它 ...

  6. UESTC 900 方老师炸弹 --Tarjan求割点及删点后连通分量数

    Tarjan算法. 1.若u为根,且度大于1,则为割点 2.若u不为根,如果low[v]>=dfn[u],则u为割点(出现重边时可能导致等号,要判重边) 3.若low[v]>dfn[u], ...

  7. poj_1144Network(tarjan求割点)

    poj_1144Network(tarjan求割点) 标签: tarjan 割点割边模板 题目链接 Network Time Limit: 1000MS Memory Limit: 10000K To ...

  8. POJ 1144 Network(无向图的割顶和桥模板题)

    http://poj.org/problem?id=1144 题意: 给出图,求割点数. 思路: 关于无向图的割顶和桥,这篇博客写的挺不错,有不懂的可以去看一下http://blog.csdn.net ...

  9. POJ 1144 Network(Tarjan求割点)

    Network Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 12707   Accepted: 5835 Descript ...

随机推荐

  1. (二分查找 结构体) leetcode33. Search in Rotated Sorted Array

    Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e. ...

  2. python之shelve模块详解

    一.定义 Shelve是对象持久化保存方法,将对象保存到文件里面,缺省(即默认)的数据存储文件是二进制的. 二.用途 可以作为一个简单的数据存储方案. 三.用法 使用时,只需要使用open函数获取一个 ...

  3. Docker:企业级私有仓库harbor[十六]

    一.安装配置 1.下载安装包 链接:https://pan.baidu.com/s/1Z9I7zYXSt-8ve3lFT2YCeg 提取码:iuqj 2.安装docker和docker-compose ...

  4. Mybatis-批量执行

    一.使用动态SQL 中的 Foreach 批量插入 1.MySQL // 实体类 public class MyUser { private Integer id; private String na ...

  5. Hadoop记录- Yarn scheduler队列采集

    #!/bin/sh ip=10.116.100.11 port=8088 export HADOOP_HOME=/app/hadoop/bin rmstate1=$($HADOOP_HOME/yarn ...

  6. C语言运算符优先级总结

    一 写在开头1.1 本文内容本文内容为C语言中运算符优先级的总结.转载于:https://blog.csdn.net/huangblog/article/details/8271791,感谢原作者的付 ...

  7. 深入学习javaScript闭包(闭包的原理,闭包的作用,闭包与内存管理)

    前言 虽然JavaScript是一门完整的面向对象的编程语言,但这门语言同时也拥有许多函数式语言的特性. 函数式语言的鼻祖是LISP,JavaScript在设计之初参考了LISP两大方言之一的Sche ...

  8. 面试经验合集-Java后端<一>

    面试一:CDKHXJSYJS   时间:2018-12-29 周六 地点:航天科技大厦32楼   一 技术题目 <回忆版> 1.上下转型 2.Java异常:分类.处理.设计 3.二叉排序树 ...

  9. 预置app/apk到系统 && 预置so库进系统 && 预置普通文件和文件夹进系统

    https://blog.csdn.net/zhandoushi1982/article/details/4695460

  10. 菜鸟博客装饰分享CSS+HTML+js

    博客布局更改,各种百度,自己修改,搞成现在这样,有兴趣的朋友可以复制我下面的把自己博客覆盖了,然后在进行更改 不懂可加群问我:675678830 如果想开通打赏,用到js,需要在 下列中 博客侧边栏公 ...