概述

在一个无向图中,若任意两点间至少存在两条“点不重复”的路径,则说这个图是点双连通的(简称双连通,biconnected)

在一个无向图中,点双连通的极大子图称为点双连通分量(简称双连通分量,Biconnected Component,BCC)

性质

  1. 任意两点间至少存在两条点不重复的路径等价于图中删去任意一个点都不会改变图的连通性,即BCC中无割点
  2. 若BCC间有公共点,则公共点为原图的割点
  3. 无向连通图中割点一定属于至少两个BCC,非割点只属于一个BCC

算法

在Tarjan过程中维护一个栈,每次Tarjan到一个结点就将该结点入栈,回溯时若目标结点low值不小于当前结点dfn值就出栈直到目标结点(目标结点也出栈),将出栈结点和当前结点存入BCC

(说实话我觉得存点不比存边难理解和实现啊……下面会解释)

理解

首先申明一下,在我找到的BCC资料中,在算法实现中均将两个点和一条边构成的图称为BCC,此文章也沿用此的规定

如下图:

我猜想可能是因为割点的定义,此图中两个点均不为割点,所以此图也属于BCC?

总之做题时注意题面要求,若要求的不含此种BCC则判断每个BCC的大小即可

无向连通图中割点一定属于至少两个BCC,非割点只属于一个BCC

有了上面的规定我们也不难理解这一条了:割点就算相邻也会属于至少两个BCC;BCC间的交点都是割点,所以非割点只属于一个BCC

到一个结点就将该结点入栈

为什么用栈存储呢?因为DFS是由上到下的,而分离BCC是自下而上的,需要后进先出的数据结构——栈

回溯时若目标结点low值不小于当前结点dfn值就出栈直到目标结点(目标结点也出栈),将出栈结点和当前结点存入BCC

对于每个BCC,它在DFS树中最先被发现的点一定是割点或DFS树的树根

证明:割点是BCC间的交点,故割点在BCC的边缘,且BCC间通过割点连接,所以BCC在DFS树中最先被发现的点是割点;特殊情况是对于开始DFS的点属于的BCC,其最先被发现的点就是DFS树的树根

上面的结论等价于每个BCC都在其最先被发现的点(一个割点或树根)的子树中

这样每发现一个BCC(low[v]>=dfn[u]),就将该子树出栈,并将该子树和当前结点(割点或树根)加入BCC中。上面的操作与此描述等价

(我就是因为这个条件“将子树出栈”没理解写错了结果调了一晚上poj2942)

综上,存点是不是很好理解?存边虽然不会涉及重复问题(割点属于至少两个BCC),但会有很多无用操作。个人觉得存点也是个不错的选择。

模板

并没有模板题

 #include<cstdio>
#include<cctype>
#include<vector>
using namespace std;
struct edge
{
int to,pre;
}edges[];
int head[],dfn[],dfs_clock,tot;
int num;//BCC数量
int stack[],top;//栈
vector<int>bcc[];
int tarjan(int u,int fa)
{
int lowu=dfn[u]=++dfs_clock;
for(int i=head[u];i;i=edges[i].pre)
if(!dfn[edges[i].to])
{
stack[++top]=edges[i].to;//搜索到的点入栈
int lowv=tarjan(edges[i].to,u);
lowu=min(lowu,lowv);
if(lowv>=dfn[u])//是割点或根
{
num++;
while(stack[top]!=edges[i].to)//将点出栈直到目标点
bcc[num].push_back(stack[top--]);
bcc[num].push_back(stack[top--]);//目标点出栈
bcc[num].push_back(u);//不要忘了将当前点存入bcc
}
}
else if(edges[i].to!=fa)
lowu=min(lowu,dfn[edges[i].to]);
return lowu;
}
void add(int x,int y)//邻接表存边
{
edges[++tot].to=y;
edges[tot].pre=head[x];
head[x]=tot;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
for(int i=;i<=n;i++)//遍历n个点tarjan
if(!dfn[i])
{
stack[top=]=i;
tarjan(i,i);
}
for(int i=;i<=num;i++)
{
printf("BCC#%d: ",i);
for(int j=;j<bcc[i].size();j++)
printf("%d ",bcc[i][j]);
printf("\n");
}
return ;
}

双连通分量

Tarjan求点双连通分量的更多相关文章

  1. hdu 2460(tarjan求边双连通分量+LCA)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2460 思路:题目的意思是要求在原图中加边后桥的数量,首先我们可以通过Tarjan求边双连通分量,对于边 ...

  2. [Codeforces 555E]Case of Computer Network(Tarjan求边-双连通分量+树上差分)

    [Codeforces 555E]Case of Computer Network(Tarjan求边-双连通分量+树上差分) 题面 给出一个无向图,以及q条有向路径.问是否存在一种给边定向的方案,使得 ...

  3. C++[Tarjan求点双连通分量,割点][HNOI2012]矿场搭建

    最近在学图论相关的内容,阅读这篇博客的前提是你已经基本了解了Tarjan求点双. 由割点的定义(删去这个点就可使这个图不连通)我们可以知道,坍塌的挖煤点只有在割点上才会使这个图不连通,而除了割点的其他 ...

  4. tarjan算法求桥双连通分量 POJ 3177 Redundant Paths

    POJ 3177 Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12598   Accept ...

  5. [HNOI2012]矿场搭建(tarjan求点双)

    题目 Description 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无 ...

  6. tarjan复习笔记 双连通分量,强连通分量

    声明:图自行参考割点和桥QVQ 双连通分量 如果一个无向连通图\(G=(V,E)\)中不存在割点(相对于这个图),则称它为点双连通图 如果一个无向连通图\(G=(V,E)\)中不存在割边(相对于这个图 ...

  7. 6409. 【NOIP2019模拟11.06】困难的图论(Tarjan求点双)

    题目描述 Description 给定由 n 个点 m 条边组成的无向连通图,保证没有重边和自环. 你需要找出所有边,满足这些边恰好存在于一个简单环中.一个环被称为简单环,当且仅当它包含的所有点都只在 ...

  8. 洛谷P2860 [USACO06JAN]冗余路径Redundant Paths(tarjan求边双联通分量)

    题目描述 In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1. ...

  9. POJ 2942 Knights of the Round Table 补图+tarjan求点双联通分量+二分图染色+debug

    题面还好,就不描述了 重点说题解: 由于仇恨关系不好处理,所以可以搞补图存不仇恨关系, 如果一个桌子上面的人能坐到一起,显然他们满足能构成一个环 所以跑点双联通分量 求点双联通分量我用的是向栈中pus ...

随机推荐

  1. 【go进阶】一个简单的go服务器实现

    光阴似箭,日月如梭,在昨天我终于拿到了自己忙活了半个月的工资. 据说在7月25日有一颗小行星掠过地球,如果真的撞上来,估计31号我就不是乐呵呵的了,应该是直接没了. 如下的代码运行起来就是一个微型go ...

  2. SolidWorks学习笔记3几个草图实例

    绘制五角星 创建一个正五边形的内切圆,圆心和圆点重合,注意垂直关系. 选中所有,都设置为构造线. 依次连接直线, 点击裁剪实体,划过所要删除的线段. 绘制高度对称草图 注意事项: 最上和最下的圆心要和 ...

  3. ng-zorro等组件默认样式的修改

    https://www.jianshu.com/p/8b887c2aac06 在项目中修改ng-zorro组件默认样式的一些方法: 类名等 前加::ng-deep: 类名等 前加:root: 类名等 ...

  4. 菜鸟系列Fabric——Fabric 网络架构介绍(4)

    Fabric 网络架构介绍 1. 网络架构介绍 如图所示,fabric网络架构主要包含客户端节点.CA节点.Peer节点.Orderer节点这几个部分.并且fabric架构是安装组织来进行划分当,每个 ...

  5. [c++] 用宏定义一个函数

    要点:变量都用括号括起来,防止出错,结尾不需要;.在实际编程中,不推荐把复杂的函数使用宏,不容易调试.多行用\ 要写好C语言,漂亮的宏定义是非常重要的.宏定义可以帮助我们防止出错,提高代码的可移植性和 ...

  6. 【转贴】龙芯内核发展策略 已经支持k8s

    龙芯内核发展策略 时间:2019-06-27 15:48  来源:未知   作者:龙芯中科   点击:1002次 http://www.loongson.cn/m/view.php?aid=1118 ...

  7. 什么是云数据库RDS PostgreSQL 版

    PostgreSQL被业界誉为“最先进的开源数据库”,面向企业复杂SQL处理的OLTP在线事务处理场景,支持NoSQL数据类型(JSON/XML/hstore).支持GIS地理信息处理. 优点 NoS ...

  8. CentOS7通过YUM安装NGINX稳定版本

    创建 nginx.repo 文件 $ cd /etc/repos.d/ $ vim nginx.repo #写入以下内容 [nginx-stable] name=nginx stable repo b ...

  9. 使用parquet-hadoop.jar包解析hive parquet文件时,遇到FIXED_LEN_BYTE_ARRAY转换为Decimal 以及 INT96转换为timestamp问题

    在使用parquet-hadoop.jar包解析parquet文件时,遇到decimal类型的数据为乱码,具体解决方法如下: 使用parquet-Hadoop.jar解析httpfs服务提供的parq ...

  10. Eclipse安装Hadoop插件配置Hadoop开发环境

    一.编译Hadoop插件 首先需要编译Hadoop 插件:hadoop-eclipse-plugin-2.6.0.jar,然后才可以安装使用. 第三方的编译教程:https://github.com/ ...