Tarjan求点双连通分量
概述
在一个无向图中,若任意两点间至少存在两条“点不重复”的路径,则说这个图是点双连通的(简称双连通,biconnected)
在一个无向图中,点双连通的极大子图称为点双连通分量(简称双连通分量,Biconnected Component,BCC)
性质
- 任意两点间至少存在两条点不重复的路径等价于图中删去任意一个点都不会改变图的连通性,即BCC中无割点
- 若BCC间有公共点,则公共点为原图的割点
- 无向连通图中割点一定属于至少两个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求点双连通分量的更多相关文章
- hdu 2460(tarjan求边双连通分量+LCA)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2460 思路:题目的意思是要求在原图中加边后桥的数量,首先我们可以通过Tarjan求边双连通分量,对于边 ...
- [Codeforces 555E]Case of Computer Network(Tarjan求边-双连通分量+树上差分)
[Codeforces 555E]Case of Computer Network(Tarjan求边-双连通分量+树上差分) 题面 给出一个无向图,以及q条有向路径.问是否存在一种给边定向的方案,使得 ...
- C++[Tarjan求点双连通分量,割点][HNOI2012]矿场搭建
最近在学图论相关的内容,阅读这篇博客的前提是你已经基本了解了Tarjan求点双. 由割点的定义(删去这个点就可使这个图不连通)我们可以知道,坍塌的挖煤点只有在割点上才会使这个图不连通,而除了割点的其他 ...
- tarjan算法求桥双连通分量 POJ 3177 Redundant Paths
POJ 3177 Redundant Paths Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 12598 Accept ...
- [HNOI2012]矿场搭建(tarjan求点双)
题目 Description 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无 ...
- tarjan复习笔记 双连通分量,强连通分量
声明:图自行参考割点和桥QVQ 双连通分量 如果一个无向连通图\(G=(V,E)\)中不存在割点(相对于这个图),则称它为点双连通图 如果一个无向连通图\(G=(V,E)\)中不存在割边(相对于这个图 ...
- 6409. 【NOIP2019模拟11.06】困难的图论(Tarjan求点双)
题目描述 Description 给定由 n 个点 m 条边组成的无向连通图,保证没有重边和自环. 你需要找出所有边,满足这些边恰好存在于一个简单环中.一个环被称为简单环,当且仅当它包含的所有点都只在 ...
- 洛谷P2860 [USACO06JAN]冗余路径Redundant Paths(tarjan求边双联通分量)
题目描述 In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1. ...
- POJ 2942 Knights of the Round Table 补图+tarjan求点双联通分量+二分图染色+debug
题面还好,就不描述了 重点说题解: 由于仇恨关系不好处理,所以可以搞补图存不仇恨关系, 如果一个桌子上面的人能坐到一起,显然他们满足能构成一个环 所以跑点双联通分量 求点双联通分量我用的是向栈中pus ...
随机推荐
- 【VS开发】C++线程安全
我们是多么渴望各种C++类都是多线程安全的,然而一旦涉及到对象间的交互,这样的渴望可能就只能是奢望了.下面,我们以设计一个双向链结点为例,看看要使其多线程安全将会带来一些什么问题. class Dou ...
- 客户端数据存储cookie、localStoeage、sessionStorage(小记)
一.数据存储分为客户端存储和服务端存储 1.而对于客户端存储,在html5以前只能通过cookie来实现:html 5以后增加了web存储(实际保存本地)的功能 (1)对于web存储有两个标准: ...
- 关于Linux文本处理“三剑客”的一些小操作。
Linux文本处理“三剑客”,即grep.sed.awk,这是Linux中最核心 的3个命令. 一.首先做个简单的介绍: 1.awk:linux三剑客老大,过滤,输出内容,一门语言.NR代表行号. 2 ...
- 第三周课程总结&实验报告一
实验一 Java开发环境与简单Java程序 一.实验目的 熟悉JDK开发环境 熟练掌握结构化程序设计方法 二.实验内容 1.在此处输入标题打印输出所有的"水仙花数",所谓" ...
- xshell设置
登录脚本: #定义rz,sz自动下载路径 #保持窗口活动状态, 空闲时每120秒发送一个回车
- 课程计划安排 ver: 2016-12-14
录的越多,后续肯定会涨价. <x86 从实模式到保护模式> 这本书涉及到除了汇编语言,还有一些计算机架构和操作系统方面相关的知识点. 不仅为学习高级编程语言打下了非常扎实的基础,学完C++ ...
- 【转贴】Windows常用命令实例
Windows常用命令实例 https://www.cnblogs.com/linyfeng/p/6261629.html 熟练使用DOS常用命令有助于提高工作效率. 1.windows+R:打开运行 ...
- Shell初学(六)Linux Shell 时间运算以及时间差计算方法
Linux Shell 时间运算以及时间差计算方法 时间的加减,以及时间差的计算. 1. 时间加减 这里处理方法,是将基础的时间转变为时间戳,然后,需要增加或者改变时间,变成 秒. 如:1990-01 ...
- MySQL教程详解之存储引擎介绍及默认引擎设置
什么是存储引擎? 与其他数据库例如Oracle 和SQL Server等数据库中只有一种存储引擎不同的是,MySQL有一个被称为“Pluggable Storage Engine Architectu ...
- Python input/output boilerplate for competitive programming
The following code is my submission for Codeforces 1244C The Football Season. import io import sys i ...