双连通分量

参考博客: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. [Unity工具]搭建lua环境(IDEA)

    一.下载IDEA 地址:https://www.jetbrains.com/idea/ 这里我的版本是IntelliJ IDEA Community Edition 2020.2.4 x64 二.断点 ...

  2. mininet配置命令

    Mininet实验手册 一.安装 1.  直接使用带有完整软件的VM(略) 2.  源码安装 1)  下载 git clone git://github.com/mininet/mininet 2)  ...

  3. struts 1.x框架记录

    strus-config.xml 项目目录最顶层建立配置文件strus-config.xml action 通过type绑定java类,可通过attribute被引用 MyLoginForm.java ...

  4. redis的数据操作和python操作redis+关系非关系数据库差异

    关系型数据库(RMDBS) 数据库中表与表的数据之间存在某种关联的内在关系,因为这种关系,所以我们称这种数据库为关系型数据库. 典型:Mysql/MariaDB.postgreSQL.Oracle.S ...

  5. 解析极限编程-拥抱变化_V2

    作者:Kent Beck 第一章 极限编程定义 XP(极限编程):extreme programming,适用于中小型团队在需求不明确或迅速变化的情况下进行软件开发的轻量级方法学. 第二章 学习开车 ...

  6. mybatis-plus update的三种方式

    参考博客:https://blog.csdn.net/weixin_44162337/article/details/107828366 1.最常见:根据id更新,xxxService.updateB ...

  7. Z 函数

    简单记一下,避免忘记. z 函数 对于字符串 \(S\),我们将 \(z(i)\) 定义为从 \(i\) 开始的后缀与 \(S\) 的最长公共前缀的长度. \(O(n)\) 求出 z 函数 我们添加一 ...

  8. 示例:iptables限制ssh链接服务器

    linux服务器默认通过22端口用ssh协议登录,这种不安全.今天想做限制,即允许部分来源ip连接服务器. 案例目标:通过iptables规则限制对linux服务器的登录. 处理方法:编写为sh脚本, ...

  9. MyBatisPlus---DQL编程控制

    MP将书写复杂的SQL查询条件进行了封装,使用编程的形式完成查询条件的组合. 一.条件查询 package com.itheima; import com.baomidou.mybatisplus.c ...

  10. 「java技术干货」switch分支结构详解

    前言 在上一篇文章中,壹哥给大家介绍了Java里的顺序.分支.循环结构的概念,并且重点给大家讲解了分支结构中的条件分支.并在条件分支中,详细地给大家讲解了if条件分支的使用.现在我们应该知道,if条件 ...