【概念】

1.双连通分量:对于一个无向图,其边/点连通度大于1,满足任意两点之间,能通过两条或两条以上没有任何重复边的路到达的图,即删掉任意边/点后,图仍是连通的

2.分类:

1)点双连通图:点连通度大于 1 的图

2)边双连通图:边连通度大于 1 的图

【原理】

1.求点双连通分量

求点双连通分量可以在求割点的同时用栈维护。

在搜索图时,每找到一条树枝边或后向边(非横叉边),就把这条边加入栈中。如果遇到满足 dfn(u)<=low(v),说明 u 是一个割点,同时把边从栈顶一个个取出,直到遇到了边 (u,v),取出的这些边与其关联的点,就组成一个点双连通分支。

割点可以属于多个点双连通分支,其余点和每条边只属于且属于一个点双连通分支。

2.求边双连通分量

求边双连通分量时,需要先求出桥,然后把桥全部去掉,原图变成多个连通块,此时每个连通块就是一个边双连通分量。

桥不属于任何一个边双连通分量,其余的边和每个顶点都属于且只属于一个边双连通分量

【过程】

1.求点双连通分量

1)Tarjan 求割点

2)每找到一个割点,将它上面的所有点弹出栈,所得到的点集就是点双连通分量

2.求边双连通分量

1)Tarjan 找桥

2)删除桥

3)剩余各部分即为边双连通分量

【实现】

1.求点双连通分量

int n,m;
vector<int> G[N];
vector<int> bcc[N];//包含i号点双连通分量的所有结点
int dfn[N];
bool iscut[N];//记录i结点是否是割点
int bccno[N];//记录第i个点属于第几号点双连通分量
int block_cnt;//时间戳
int bcc_cnt;//记录点双连通分量个数
struct Edge {int x;int y;
};
stack<Edge> S;
int Tarjan(int x,int father) {int lowx=dfn[x]=++block_cnt;int child=0;//子节点数目for(int i=0; i<G[x].size(); i++) {int y=G[x][i];//当前结点的下一结点Edge e;e.x=x;e.y=y;if(dfn[y]==0) { //若未被访问过S.push(e);child++;//未访问过的节点才能算是x的孩子int lowy=Tarjan(y,x);lowx=min(lowx,lowy);if(lowy>=dfn[x]) {iscut[x]=true;//x点是割点bcc_cnt++;bcc[bcc_cnt].clear();while(true) {Edge temp=S.top();S.pop();if(bccno[temp.x]!=bcc_cnt) {bcc[bcc_cnt].push_back(temp.x);bccno[temp.x]=bcc_cnt;}if(bccno[temp.y]!=bcc_cnt) {bcc[bcc_cnt].push_back(temp.y);bccno[temp.y]=bcc_cnt;}if(temp.x==x && temp.y==y)break;}}} else if(dfn[y]<dfn[x] && y!=father) { //y!=father确保了(x,y)是从x到y的反向边S.push(e);lowx=min(lowx,dfn[y]);}}if(father<0 && child==1 )//x若是根且孩子数<=1,那x就不是割点iscut[x]=false;return lowx;
}
int main() {scanf("%d%d",&n,&m);for(int i=0; i<n; i++)G[i].clear();while(m--) {int x,y;scanf("%d%d",&x,&y);G[x].push_back(y);G[y].push_back(x);}bcc_cnt=0;block_cnt=0;memset(dfn,0,sizeof(dfn));memset(iscut,0,sizeof(iscut));memset(bccno,0,sizeof(bccno));for(int i=0; i<n; i++)if(!dfn[i])Tarjan(i,-1);printf("点-双连通分量一共%d个\n",bcc_cnt);for(int i=1; i<=bcc_cnt; i++){printf("第%d个点-双连通分量包含以下点:\n",i);sort(&bcc[i][0],&bcc[i][0]+bcc[i].size()); //对vector排序,使输出的点从小到大for(int j=0; j<bcc[i].size(); j++)printf("%d ",bcc[i][j]);printf("\n");}return 0;
}

2.求边双连通分量

struct Edge {int x;int yl
} edge[N];
int n,m;
int dfn[N],low[N];
int bccno[N];
vector<int> G[N],bcc[N];
int sig,block_cnt;
bool g[N][N],isbridge[N];
void tarjan(int x,int father) {dfn[x]=low[x]=++block_cnt;for(int i=0; i<G[x].size(); i++) {int y=edge[G[x][i]].y;if(!dfn[y]) {tarjan(y,x);low[x]=min(low[x],low[y]);if(low[y]>dfn[x]) {isbridge[G[x][i]]=1;isbridge[G[x][i]^1]=1;}} else if(dfn[y]<dfn[x] && y!=father)low[x]=min(low[x], dfn[y]);}
}
void dfs(int x) {dfn[x]=1;bccno[x]=sig;for(int i=0; i<G[x].size(); i++) {int y=G[x][i];if(isbridge[y])continue;if(!dfn[edge[y].y])dfs(edge[y].y);}
}
int main() {scanf("%d%d",&n,&m);for(int i=0; i<n; i++)G[i].clear();while(m--) {int x,y;scanf("%d%d",&x,&y);G[x].push_back(y);}sig=0;block_cnt=0;memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(isbridge,0,sizeof(isbridge));memset(bccno,0,sizeof(bccno));memset(bcc,0,sizeof(bcc));for(int i=1; i<=n; i++) //先DFS找桥if(!dfn[i])tarjan(i, -1);memset(dfn,0,sizeof(dfn));for(int i=1; i<=n; i++){ //再DFS找边双连通分量if(!dfn[i]) {sig++;dfs(i);}}printf("%d\n",sig);//边双连通分量个数return 0;
}

图论 —— 图的连通性 —— Tarjan 求双连通分量相关推荐

  1. 图论 —— 图的连通性 —— Tarjan 求割点与桥

    [概念] 1.割点 1)割点:删除某点后,整个图变为不连通的两个部分的点 2)割点集合:在一个无向图中删除该集合中的所有点,能使原图变成互不相连的连通块的点的集合 3)点连通度:最小割点集合点数 如上 ...

  2. 图论 —— 图的连通性 —— Tarjan 求强连通分量

    [概述] Tarjan 算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树. 搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量. [ ...

  3. 图论 —— 图的连通性 —— Tarjan 缩点

    缩点常应用于给一个有向图,求在图中最少要加多少条边能使得该图变成一个强连通图 首先求出该图的各个强连通分量,然后把每个强连通分量看出一个点(即缩点),最后得到了一个有向无环图(DAG) 对于一个DAG ...

  4. 图论 —— 图的连通性

    [基本概念] 1.连通图与连通分量 1)连通图:无向图 G 中,若对任意两点,从顶点 Vi 到顶点 Vj 有路径,则称 Vi 和 Vj 是连通的,图 G 是一连通图 2)连通分量:无向图 G 的连通子 ...

  5. Redundant Paths POJ - 3177(tarjan+边双连通分量)

    题意: 有n个牧场,要求从一个牧场到另一个牧场,要求至少要有2条独立的路可以走.现已有m条路,求至少要新建多少条路,使得任何两个牧场之间至少有两条独立的路.两条独立的路是指:没有公共边的路,但可以经过 ...

  6. Tarjan的求双连通分量算法

    哎~气死我了!昨天晚上都写好了--一不小心把网页关了,写的全没了--MD 什么是双连通分量DCC(Double connected component)? 首先说一下一个无向连通图,若去掉任一点或任一 ...

  7. 图论 —— 图的连通性 —— 有桥连通图加边变边双连通图

    对于一个有桥的连通图,加边变成边双连通图 1.求出所有的桥,然后删除这些桥边.剩下的每个连通块都是一个双连通子图. 2.把每个双连通子图收缩为一个顶点. 3.加回桥边,统计度为1的节点的个数(叶节点的 ...

  8. 图论 —— 图的连通性 —— 传递闭包

    [概述] 传递闭包:对于一个节点 i,如果 j 能到 i,i 能到 k,那么 j 就能到 k,求传递闭包,就是把图中所有满足这样传递性的节点计算出来,计算完成后,就知道任意两个节点之间是否相连. 简单 ...

  9. 图论 —— 图的连通性 —— Kosaraju 算法

    [概述] Kosaraju 算法是最容易理解,最通用的求强连通分量的算法,其关键的部分是同时应用了原图 G 和反图 GT . [基本思想] 1.对原图 G 进行 DFS 搜索,计算出各顶点完成搜索的时 ...

最新文章

  1. 时间罗盘html源代码_重磅!Vue 3.0源代码公布后,究竟有哪些变更?
  2. C++之类模板最简单的使用
  3. [bbk5307]第76集 第9章 -数据库性能维护 03
  4. java左手握右手_在队列中,向中看齐举哪个手?
  5. C++基础——关于模板的技巧性基础知识(typename、成员模板、模板的模板参数)
  6. JAVA多线程----用--取钱问题1
  7. c语言中代码中的作用,C语言中#的神奇作用
  8. Android系统签名文件
  9. C# 人民币大写金额转换
  10. hazy的面试小笔记之Spring(持续更新)
  11. SpringBoot将图片/文件传至前端
  12. 基于docker实现openwrt软路由与OMV(NAS)应用
  13. 如何在离开计算机后加密锁定,如何对企业电脑硬盘文件进行加密?
  14. perl中grep用法总结
  15. 初心始终 殊途同归 | SCTF同期个人能力认证考核专场报名开启
  16. 360类redis存储服务Pika的安装和使用
  17. 借用excel 设计 fasterport 表格,主要是考虑 转回excel 整齐好看
  18. 1063 计算谱半径
  19. luogu P2221 [HAOI2012]高速公路
  20. 面试 需要警惕三个问题

热门文章

  1. 4万次下载,我的这本电子书连续数月蝉联阿里云下载榜冠军!!!
  2. Java开发者必备:超全的Java问题排查工具单
  3. 低代码开发初体验一分钟——Jeecg-Boot 在线报表开发
  4. Java容器 | 基于源码分析List集合体系
  5. Hadoop--xsync分发脚本
  6. UML类图操作(一)
  7. Python(pycharm)在windows下路径 ( ' / ' 与' \ ' )的问题
  8. PAT 1003 Sharing (25)
  9. cocoapods的安装与使用
  10. Python知识总结(二)