双连通分量

参考博客:https://www.cnblogs.com/jiamian/p/11202189.html#_2

概念

双连通分量有点双连通分量和边双连通分量两种。若一个无向图中的去掉任意一个节点(一条边)都不会改变此图的连通性,即不存在割点(桥),则称作点(边)双连通图。

点双连通和边双连通

在一张连通的无向图中,对于两个点 \(u\) 和 \(v\),如果无论删去哪条边(只能删去一条)都不能使它们不连通,我们就说 \(u\) 和 \(v\) 边双连通。

在一张连通的无向图中,对于两个点 \(u\) 和 \(v\),如果无论删去哪个点(只能删去一个,且不能删 \(u\) 和 \(v\) 自己)都不能使它们不连通,我们就说 \(u\) 和 \(v\) 点双连通。

边双连通具有传递性,即,若 \(x\),\(y\) 边双连通,\(y\),\(z\) 边双连通,则 \(x\),\(z\) 边双连通。

点双连通:删掉一个点之后,图仍联通

边双连通:删掉一条边之后,图仍联通

概述

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

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

性质

  1. 任意两点间至少存在两条点不重复的路径等价于图中删去任意一个点都不会改变图的连通性,即 BCC 中无割点。

  2. 若 BCC 间有公共点,则公共点为原图的割点。

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

算法

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

点双连通分量

我们从割点的定义可以得知,当你把割点去掉的时候原来的一个强连通分量会变成两个或以上的强连通分量,但是我们可以知道,去掉割点以外的点对于连通块的数量是没有影响的,所以我们可以知道,割点加上他能分成的连通块的各个点可以组成一个点双连通分量,就像下面这个图:

一眼能看出来的就是 \(2\),\(3\) 都是割点,我们可以发现 \(3,6,7\) 和 \(0,1,2,3,4,5\) 都是点双连通分量。

我们根据上面提到的性质可以得知,割点至少在两个点双连通分量里,所以我们在弹栈存答案的时候不要把割点一起弹出,直到这个割点分出的连通块的点双连通分量都找完的时候再进行弹栈。

P8435 【模板】点双连通分量

code:

#include<bits/stdc++.h>
#define N 10001000
using namespace std;
struct sb{int u,v,next;}e[N];
int n,m,cnt,head[N],dfn[N],low[N],tot,stk[N],top,bcc;//bcc存放当前的点双连通分量的数量
vector<int>ans[N];//存放答案
inline void add(int u,int v)
{
e[++cnt].u=u;
e[cnt].v=v;
e[cnt].next=head[u];
head[u]=cnt;
}
inline void tarjan(int x,int fa)//fa是x的父节点
{
dfn[x]=low[x]=++tot;
stk[++top]=x;
int ch=0;//ch存放子节点的数量
for(int i=head[x];i;i=e[i].next)
{
int v=e[i].v;
if(!dfn[v])//如果当前点还没有搜索过
{
ch++;//子节点加一
tarjan(v,x);//继续往下搜
low[x]=min(low[x],low[v]);//正常更新low[x]的值
if(low[v]>=dfn[x])//割点的判定条件
{
bcc++;//点双连通分量的数量加1
while(stk[top+1]!=v)//如果上一个弹出的栈顶元素不是v的话就一直弹
ans[bcc].push_back(stk[top--]);//将当前点放入栈中
ans[bcc].push_back(x);//最后把割点给加进去
}
}
else if(v!=fa)//不能用父节点来更新当前点的low值
low[x]=min(low[x],dfn[v]);
}
if(fa==0&&ch==0)//特判只有一个点的情况
ans[++bcc].push_back(x);
}
signed main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
{
top=0;
tarjan(i,0);
}
}
cout<<bcc<<endl;
for(int i=1;i<=bcc;i++)
{
int siz=ans[i].size();
cout<<siz<<" ";
for(int j=0;j<siz;j++)
cout<<ans[i][j]<<" ";
cout<<endl;
}
return 0;
}

另一种写法?

code:

void tarjan(int x,int fa)
{
dfn[x]=low[x]=++tot;
stk[++top]=x;
if(x==fa&&head[x]==0)
{
ans[++bcc].push_back(x);
return;
}
int ch=0;
for(int i=head[x];i;i=e[i].next)
{
int v=e[i].v;
if(!dfn[v])
{
tarjan(v,fa);
low[x]=min(low[x],low[v]);
if(low[v]>=dfn[x])
{
ch++;
if(x!=fa||ch>1)
vis[x]=1;
bcc++;
int y;
while(y!=v)
{
y=stk[top--];
ans[bcc].push_back(y);
}
ans[bcc].push_back(x);
}
}
else if(x!=fa)
low[x]=min(low[x],dfn[v]);
}
}

边双连通分量

割边,也就是桥,会找吧,代码就和缩点有一点不同,就是把 if(low[v]>=dfn[x]) 改成 if(low[v]>dfn[x])。

我们都知道把割边去掉之后就会多出一些强连通分量,如果要是不是割边的话,那就对连通块的数量没有影响,所以我们可以找出所有的割边,然后 dfs 一遍找出连通块。

来看下面这张图

可以看出里面不是割边的边只有 {1,3},{1,2},{2,3};我们可以发现一个 DCC 里面的边是没有割边的,所以我们把割边标记后 dfs 是正确的。

P8436 【模板】边双连通分量

code:

#include<bits/stdc++.h>
#define N 2000005
using namespace std;
int n,m,head[N],dfn[N],low[N],dcc,vis[N],tot,cnt=1;
struct sb{int u,v,next,flag;}e[N<<1];
vector<int>ans[N];
inline void add(int u,int v)
{
e[++cnt].u=u;
e[cnt].v=v;
e[cnt].next=head[u];
head[u]=cnt;
}
void tarjan(int x,int fa)
{
dfn[x]=low[x]=++tot;
for(int i=head[x];i;i=e[i].next)
{
int v=e[i].v;
if(!dfn[v])
{
tarjan(v,x);
low[x]=min(low[x],low[v]);
if(low[v]>dfn[x])
e[i].flag=e[i^1].flag=1;
}
else if(v!=fa)low[x]=min(low[x],dfn[v]);
}
}
void dfs(int x)
{
ans[dcc].push_back(x);
vis[x]=1;
for(int i=head[x];i;i=e[i].next)
{
int v=e[i].v;
if(vis[v]||e[i].flag)continue;
dfs(v);
}
}
signed main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i,0);
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
dcc++;
dfs(i);
}
}
cout<<dcc<<endl;
for(int i=1;i<=dcc;i++)
{
int siz=ans[i].size();
cout<<siz<<" ";
for(int j=0;j<siz;j++)
cout<<ans[i][j]<<" ";
cout<<endl;
}
return 0;
}

点&边双连通分量的更多相关文章

  1. POJ2942 Knights of the Round Table[点双连通分量|二分图染色|补图]

    Knights of the Round Table Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 12439   Acce ...

  2. 【Codefoces487E/UOJ#30】Tourists Tarjan 点双连通分量 + 树链剖分

    E. Tourists time limit per test: 2 seconds memory limit per test: 256 megabytes input: standard inpu ...

  3. 【BZOJ-2730】矿场搭建 Tarjan 双连通分量

    2730: [HNOI2012]矿场搭建 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1602  Solved: 751[Submit][Statu ...

  4. hihoCoder 1184 连通性二·边的双连通分量

    #1184 : 连通性二·边的双连通分量 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在基本的网络搭建完成后,学校为了方便管理还需要对所有的服务器进行编组,网络所的老 ...

  5. HDU 5458 Stability(双连通分量+LCA+并查集+树状数组)(2015 ACM/ICPC Asia Regional Shenyang Online)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5458 Problem Description Given an undirected connecte ...

  6. 点/边 双连通分量---Tarjan算法

    运用Tarjan算法,求解图的点/边双连通分量. 1.点双连通分量[块] 割点可以存在多个块中,每个块包含当前节点u,分量以边的形式输出比较有意义. typedef struct{ //栈结点结构 保 ...

  7. Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)【转】【修改】

    一.基本概念: 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成 ...

  8. poj3177 && poj3352 边双连通分量缩点

    Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12676   Accepted: 5368 ...

  9. 【POJ 2942】Knights of the Round Table(点双连通分量,二分图染色)

    圆桌会议必须满足:奇数个人参与,相邻的不能是敌人(敌人关系是无向边). 求无论如何都不能参加会议的骑士个数.只需求哪些骑士是可以参加的. 我们求原图的补图:只要不是敌人的两个人就连边. 在补图的一个奇 ...

  10. 【POJ 3177】Redundant Paths(边双连通分量)

    求出每个边双连通分量缩点后的度,度为1的点即叶子节点.原图加上(leaf+1)/2条边即可变成双连通图. #include <cstdio> #include <cstring> ...

随机推荐

  1. 生成uui

    1.安装uuid包 go get github.com/google/uuid 2.目录结构 3.uuid.go package uuid import ( "github.com/goog ...

  2. Spring bean注入问题:NoUniqueBeanDefinitionException解决方案归纳

    引言 spring实现的bean自动注入在项目开发中是一个经常使用到的功能,但自动装配两个或多个bean时,会抛出NoUniqueBeanDefinitionException:No qualifyi ...

  3. Oracle表主键作为外键都用在哪些表查询

    Oracle中,如果设置了外键,删除数据时,必须将外键关联一并删除,但是如果对项目不是很熟悉时,我们无法判断到底都在哪些表中有外键关联,以下提供了一个查询的SQL,可以通过数据库查询,查找到所有的外键 ...

  4. 通用图像分割任务- 使用 Mask2Former 和 OneFormer

    本文介绍两个领先的图像分割神经网络模型: Mask2Former 和 OneFormer.相关模型已经在 Transformers 提供. Transformers 是一个开源库,提供了很多便捷的先进 ...

  5. 文件上传 upload-labs Pass-17 二次渲染

    Pass-17 审计源码 $is_upload = false; $msg = null; if (isset($_POST['submit'])){ // 获得上传文件的基本信息,文件名,类型,大小 ...

  6. 关于IDEA发出基于APR的本地库加载失败错误的解决------->求解决!

    问题描述 在没有使用Maven项目启动该Project时,Tomcat可以正常使用,但在这里会显示这样的错误: 这个错误,已经查了两天了,相关文件以及解决方法已经翻烂了,还没有解决,放出来集思广益一下 ...

  7. Cesium近地天空盒,解决图片旋转问题

    前言 当我们使用官网的例子设置天空盒后,会发现天空云彩是斜的,比如下边这张图:通过查阅网上资料,需要修改cesium的源码,以下是修改后skybox的源码,在自己的项目中引入即可: 实现代码 cons ...

  8. GUI编程--1

    GUI编程--1 GUI是什么 (Graphical User Interface),即用户图形界面编程. 怎么玩 平时怎么运用 组件 窗口 弹窗 面板 文本框 列表框 按钮 图片 监听事件 1.简介 ...

  9. 5.Web信息收集

    Web信息收集 目录 Web信息收集 1.whois查询 2.服务器操作系统的识别 3.服务器加固 4.服务版本识别 5.常见组合: 6.指纹识别 7.敏感路径识别 8.历史漏洞信息收集 1.whoi ...

  10. 在 Rainbond 上使用 Curve 云原生存储

    Curve 是网易主导自研的现代化存储系统, 目前支持文件存储(CurveFS)和块存储(CurveBS). CurveBS 的核心应用场景主要包括: 虚拟机/容器的性能型.混合型.容量型云盘或持久化 ...