双连通分量

参考博客: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. 【Flutter】环境搭建(Windows+Android Studio 3.6.1)

    最近参加的项目需要用到Flutter框架进行iOS/Android双端开发,然而第一步环境搭建的过程就忙活了一整个晚上,直到现在终于有时间静下心来整理一下搭建过程中遇到的困难. 0x00 Flutte ...

  2. Windows10系统快速安装.NET Framework3.5的方法&常见问题处理方法

    Windows10系统快速安装.NET Framework3.5的方法&常见问题处理方法 因为我的win10想了办法来禁止自动更新,就无法照正常办法安装.NET Framework3.5,解决 ...

  3. TProtocolException: Required field 'type' is unset! Struct:TPrimitiveTypeEntry(type:null)

    org.apache.thrift.protocol.TProtocolException: Required field 'type' is unset! Struct:TPrimitiveType ...

  4. fatal: unable to access ' ' OpenSSL SSL_read: Connection was reset, errno 10054

    描述: git clone ...时报错 fatal: unable to access 'https://github.com/github-eliviate/papers.git/': OpenS ...

  5. 痞子衡嵌入式:2021 TencentOS Tiny AIoT应用创新大赛 - 初赛阶段的38个作品速览

    腾讯 TencentOS 团队于2021年12月8日联合恩智浦半导体.安谋科技发起的线上开发者活动 - TencentOS Tiny AIoT 应用创新大赛目前已经进入到了最后的决赛阶段. 参赛者的作 ...

  6. SublimeText实现Markdown快速预览

    SublimeText是什么? SublimeText是一个文本编辑器,同时也是一个先进的代码编辑器.SublimeText具有漂亮的用户界面和强大的功能,它的主要功能包括:拼写检查,书签,完整的Py ...

  7. Java并发小结01

    Java并发小结01 主要参考自<实战Java高并发程序设计>. 需要知道的概念 - 同步与异步 - 并发与并行 - 临界区 - 阻塞与非阻塞 - 死锁.饥饿.活锁 同步与异步 同步:同步 ...

  8. PicGo+Typora+Github图床配置步骤(一键上传本地图片)

    PicGo+Typora+Github图床配置步骤(一键上传本地图片) 一.配置前的准备 首先你需要有一个Github账号[GitHub]. 然后下载PicGo图片上传工具[PicGo]和Typora ...

  9. MySQL查询练习 (转载)

    转载 @香草味的橙子 侵删 Evernote Export body, td { font-family: 微软雅黑; font-size: 10pt } mysql查询练习 新建一个查询用的数据库: ...

  10. Debiased Contrastive Learning of Unsupervised Sentence Representations 论文精读

    1. 介绍(Introduction) 问题: 由PLM编码得到的句子表示在方向上分布不均匀, 在向量空间中占据一个狭窄的锥形区域, 这在很大程度上限制了它们的表达能力. 已有的解决办法: 对比学习. ...