之前一直对tarjan算法的这几种不同应用比较混淆...我太弱啦!

被BLO暴虐滚过来

用tarjan求点双,很多神犇都给出了比较详细的解释和证明,在这里就不讲了(其实是这只蒟蒻根本不会orz)

这里放一下定义

这篇博客主要讲一讲求割点,点双的板子实现以及详细解释

先yy这样一道题:

有n个点,m条边,保证给出的是一个联通图,求割点

(真·最裸割点)

这道题就可以用下面这份代码实现

  1. #pragma GCC optimize("O2")
  2. #include<iostream>
  3. #include<cstdio>
  4. #include<cstring>
  5. #include<algorithm>
  6. #include<cmath>
  7. #include<queue>
  8. #include<stack>
  9. #include<set>
  10. #include<map>
  11. #include<limits.h>
  12. #include<ctime>
  13. #define N 100001
  14. typedef long long ll;
  15. const int inf=0x3fffffff;
  16. const int maxn=2017;
  17. using namespace std;
  18. inline int read()
  19. {
  20. int f=1,x=0;char ch=getchar();
  21. while(ch>'9'|ch<'0')
  22. {
  23. if(ch=='-')
  24. f=-1;
  25. ch=getchar();
  26. }
  27. while(ch<='9'&&ch>='0')
  28. {
  29. x=(x<<3)+(x<<1)+ch-'0';
  30. ch=getchar();
  31. }
  32. return f*x;
  33. }
  34. struct tsdl{
  35. int to,w,next ;
  36. } edge[N*4];
  37. int tot,head[N],dfn[N],low[N],fa[N],son[N],size[N];
  38. bool iscut[N];
  39. void add(int ui,int vi)
  40. {
  41. edge[++tot].next=head[ui];
  42. edge[tot].to=vi;
  43. head[ui]=tot;
  44. }
  45. void tarjan(int x)
  46. {
  47. dfn[x]=low[x]=++tot;
  48. size[x]=1;
  49. for(int i=head[x];i!=-1;i=edge[i].next)
  50. {
  51. int v=edge[i].to;
  52. if(v==fa[x])continue;
  53. if(!dfn[v])
  54. {
  55. son[x]++;//x的子树++
  56. fa[v]=x;//v的父亲是x
  57. tarjan(v);
  58. size[x]+=size[v];//x所连节点的个数
  59. low[x]=min(low[x],low[v]);
  60. if(dfn[x]<=low[v])
  61. {
  62. iscut[x]=1;//找到割点
  63. }
  64. }
  65. else low[x]=min(low[x],dfn[v]);
  66. }
  67. if(fa[x]==0&&son[x]<=1)
  68. iscut[x]=0;//根节点,特判处理
  69. }
  70. int main()
  71. {
  72. memset(head,-1,sizeof(head));
  73. int n=read(),m=read();
  74. for(int i=1;i<=m;i++)
  75. {
  76. int u=read(),v=read();
  77. add(u,v);
  78. add(v,u);
  79. }
  80. for(int i=1;i<=n;i++)
  81. {
  82. if(!dfn[i])tarjan(i);
  83. }
  84. for(int i=1;i<=n;i++)
  85. if(iscut[i])cout<<i<<endl;
  86. }

例如我们输入

5 5
1 2
2 3
1 3
3 4
4 5

程序完美の输出了 3,4

是不是很棒啊x

那么我们要统计点双的数量要怎么处理呢?

显然能发现,我们求出一个割点之后,被割点分成的几部分都能分别与这个割点组成一个点双

那么我们只需要统计每个割点被访问次数即可

更改之后的代码:

  1. #pragma GCC optimize("O2")
  2. #include<iostream>
  3. #include<cstdio>
  4. #include<cstring>
  5. #include<algorithm>
  6. #include<cmath>
  7. #include<queue>
  8. #include<stack>
  9. #include<set>
  10. #include<map>
  11. #include<limits.h>
  12. #include<ctime>
  13. #define N 100001
  14. typedef long long ll;
  15. const int inf=0x3fffffff;
  16. const int maxn=2017;
  17. using namespace std;
  18. inline int read()
  19. {
  20. int f=1,x=0;char ch=getchar();
  21. while(ch>'9'|ch<'0')
  22. {
  23. if(ch=='-')
  24. f=-1;
  25. ch=getchar();
  26. }
  27. while(ch<='9'&&ch>='0')
  28. {
  29. x=(x<<3)+(x<<1)+ch-'0';
  30. ch=getchar();
  31. }
  32. return f*x;
  33. }
  34. struct tsdl{
  35. int to,w,next ;
  36. } edge[N*4];
  37. int tot,head[N],dfn[N],low[N],fa[N],son[N],size[N];
  38. bool iscut[N];
  39. void add(int ui,int vi)
  40. {
  41. edge[++tot].next=head[ui];
  42. edge[tot].to=vi;
  43. head[ui]=tot;
  44. }
  45. int ans;
  46. void tarjan(int x)
  47. {
  48. if(iscut[x])ans++;//统计x1
  49. dfn[x]=low[x]=++tot;
  50. size[x]=1;
  51. int tmp=0;
  52. for(int i=head[x];i!=-1;i=edge[i].next)
  53. {
  54. int v=edge[i].to;
  55. if(edge[i].to==fa[x])continue;
  56. if(!dfn[v])
  57. {
  58. son[x]++;
  59. fa[v]=x;
  60. tarjan(v);
  61. size[x]+=size[v];
  62. low[x]=min(low[x],low[v]);
  63. if(dfn[x]<=low[v])
  64. {
  65. iscut[x]=1;//找到割点
  66. ans++;//统计x2
  67. }
  68. }
  69. else low[x]=min(low[x],dfn[v]);
  70. }
  71. if(fa[x]==0&&son[x]<=1)
  72. iscut[x]=0;//根节点,特判处理
  73. }
  74. int main()
  75. {
  76. memset(head,-1,sizeof(head));
  77. int n=read(),m=read();
  78. for(int i=1;i<=m;i++)
  79. {
  80. int u=read(),v=read();
  81. add(u,v);
  82. add(v,u);
  83. }
  84. for(int i=1;i<=n;i++)
  85. {
  86. if(!dfn[i])tarjan(i);
  87. }
  88. for(int i=1;i<=n;i++)
  89. if(iscut[i])cout<<i<<endl;
  90. cout<<ans;
  91. }
  1.  

输出就是直接

当然对他做一点小小的改动也可以实现求桥..

只需要对于每次记录iscut  改为记录二维数组cutedge[x][v]即可

需要注意的是 这里的条件不同于求割点的小于等于 这里需要low[v]严格大于dfn[x]

tarjan求双联通分量(割点,割边)的更多相关文章

  1. tarjan模板 强联通分量+割点+割边

    // https://www.cnblogs.com/stxy-ferryman/p/7779347.html ; struct EDGE { int to, nt; }e[N*N]; int hea ...

  2. tarjan求强联通分量

    tarjan求强联通分量 变量含义说明: pre[i]:i点的被访问的时钟编号,被分配后保持不变 low[i]:i点能访问的最先的点的时钟编号,随子节点改变 scc_no[i]:i点所在的强联通分量的 ...

  3. [J]computer network tarjan边双联通分量+树的直径

    https://odzkskevi.qnssl.com/b660f16d70db1969261cd8b11235ec99?v=1537580031 [2012-2013 ACM Central Reg ...

  4. POJ 3694Network(Tarjan边双联通分量 + 缩点 + LCA并查集维护)

    [题意]: 有N个结点M条边的图,有Q次操作,每次操作在点x, y之间加一条边,加完E(x, y)后还有几个桥(割边),每次操作会累积,影响下一次操作. [思路]: 先用Tarjan求出一开始总的桥的 ...

  5. BZOJ 压力 tarjan 点双联通分量+树上差分+圆方树

    题意 如今,路由器和交换机构建起了互联网的骨架.处在互联网的骨干位置的核心路由器典型的要处理100Gbit/s的网络流量. 他们每天都生活在巨大的压力之下.小强建立了一个模型.这世界上有N个网络设备, ...

  6. POJ2942 Knights of the Round Table【Tarjan点双联通分量】【二分图染色】【补图】

    LINK 题目大意 有一群人,其中有一些人之间有矛盾,现在要求选出一些人形成一个环,这个环要满足如下条件: 1.人数大于1 2.总人数是奇数 3.有矛盾的人不能相邻 问有多少人不能和任何人形成任何的环 ...

  7. Tarjan求强联通分量+缩点

    提到Tarjan算法就不得不提一提Tarjan这位老人家 Robert Tarjan,计算机科学家,以LCA.强连通分量等算法闻名.他拥有丰富的商业工作经验,1985年开始任教于普林斯顿大学.Tarj ...

  8. Tarjan算法 (强联通分量 割点 割边)

    变量解释: low 指当前节点在同一强连通分量(或环)能回溯到的dfn最小的节点 dfn 指当前节点是第几个被搜到的节点(时间戳) sta 栈 vis 是否在栈中 ans 指强连通分量的数量 top ...

  9. [hdu2460]network(依次连边并询问图中割边数量) tarjan边双联通分量+lca

    题意: 给定一个n个点m条边的无向图,q个操作,每个操作给(x,y)连边并询问此时图中的割边有多少条.(连上的边会一直存在) n<=1e5,m<=2*10^5,q<=1e3,多组数据 ...

随机推荐

  1. MyBatis - 3.Mapper XML映射文件

    SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序): cache – 给定命名空间的缓存配置. cache-ref – 其他命名空间缓存配置的引用. resultMap – 是最复杂也是 ...

  2. 现在k8s新版里,如何在每个node上运行一个带privileged的daemonset

    以前,我们会在kubelet上加--allow-prividged启动参数来实现. 而现在,更推荐的是用pod secureity policy来实现.前面的那种方式以后会被废弃. https://k ...

  3. spring+redis的集成,redis做缓存

    1.前言 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.我们都知道,在日常的应用中,数据库瓶颈是最容易出现的 ...

  4. BZOJ 1706

    题解: 倍增+floyd 首先这题比较容易想到是把每个点拆点做dij 但是这样复杂度是knlogn的 这道题的k较大,所以不行 我们考虑到每走一步,其实就是在进行一次floyd 而这个可以看成矩阵乘法 ...

  5. java生成二维码并融合模板工具类

    二维码融合模板 二维码融合图片 import java.awt.AlphaComposite; import java.awt.Graphics2D; import java.awt.Image; i ...

  6. 用面向对象重写thread 实现多次调用一个线程

    思路: 利用thread类中,run方法在子线程中调用,其他方法在主线程调用,所以将生产者写入主线程,将消费者写入run函数中在子线程中执行,完成生产者消费者模型 注意: 1. 要在 init 函数中 ...

  7. Java实现简单计算器、抽票程序

    计算器: import java.awt.BorderLayout; import java.awt.Container; import java.awt.Font; import java.awt. ...

  8. Java 之 Web前端(三)

    1.JSP a.全称:Java Server Page b.运行:翻译.编译.类装载.类实例化.(初始化.服务.销毁 (这三点为Servlet的生命周期)) 2.JSP的基本组成 a.HTML模板 注 ...

  9. POJ 2155 Matrix 【二维树状数组】(二维单点查询经典题)

    <题目链接> 题目大意: 给出一个初始值全为0的矩阵,对其进行两个操作. 1.给出一个子矩阵的左上角和右上角坐标,这两个坐标所代表的矩阵内0变成1,1变成0. 2.查询某个坐标的点的值. ...

  10. Spring Boot 项目实战(四)集成 Redis

    一.前言 上篇介绍了接口文档工具 Swagger 及项目监控工具 JavaMelody 的集成过程,使项目更加健壮.在 JAVA Web 项目某些场景中,我们需要用缓存解决如热点数据访问的性能问题,业 ...