第1节 连通性强连通、割点和桥(一)
文章目录
- 无向图割点、桥、双连通分量
- Tarjan算法求割点和桥(割边)
- 代码:
- 边双连通分量 和 点双连通分量
- 代码
- 边双连通分量 和 点双连通分量 的缩点
- 有向图的弱连通与强连通
- 强连通分量
- Kosaraju算法
- Tarjan算法
- 代码:
无向图割点、桥、双连通分量
• 给定无向联通图G=(V,E) • 对于一个点x,若从图中删除x及所有与x相连的边,图不再联通,x是G的割点
• 对于一条边e,从图中删去e,图不再联通,e的x的割边
• 一个图如果不存在割点,则它是一个点双连通图,一个图的极大点双连通子图是他的点双连
通分量。
• 一个图如果不存在割边,则它是一个边双连通图,一个图的极大边双连通子图是他的边双连
通分量。
Tarjan算法求割点和桥(割边)
时间戳dfn :第n个搜到这个点
返祖边:搜索树上一个点连向其祖先节点的边
横插边:搜索树上一个点连向它另一条支链上的点的边----在无向图中不存在
追溯值low:当前点及其子树的返祖边能连到的dfn值最小的点
如果<u,v>是搜索树的边:low[u]=min(low[u],low[v])
• u点是割点,v是u搜索树上的一个儿子:dfn[u] <= low[v] ——v的子树中没有返祖边能跨越u点;有多个儿子的根节点
比如图中的点10和点7
• 边是桥,搜索树上v是u的儿子:dfn[u]<low[v]——v的子树中没有返祖边能跨越<u,v>这条边
代码:
void tarjan(int x)//求割点
{dfn[x]=low[x]=++cnt;int flag=0;for(int i=head[x];i;i=edge[i].next){int v=edge[i].v;if(!dfn[v]){tarjan(v);low[x]=min(low[x],low[v]);if(low[v]>=dfn[x]){flag++;if(x!=root||flag>1)book[x]=1;//flag>!说明根有两个以上的儿子 }}else low[x]=min(low[x],dfn[v]);}
}
求割边:if(low[v] > dfn[x])
边双连通分量 和 点双连通分量
• 把桥删了每个连通块都是一个边双联通分量——标记出桥之后dfs一遍即可
• 点双连通分量要复杂一些——一个割点可能属于多个双联通分量
点双连通分量性质:
任意两点间至少存在两条点不重复的路径等价于图中删去任意一个点都不会改变图的连通性,即BCC中无割点
若BCC间有公共点,则公共点为原图的割点
无向连通图中割点一定属于至少两个BCC,非割点只属于一个BC
点双连通分量求法::
• 维护一个栈
• 第一次访问某个节点时,将其入栈
• 当割点判断法则中dfn[x]<=low[y]成立时,不断从栈中弹出节点,直到y被弹出,这些被弹出的点和x一起构成一个点双连通分量
代码
#include<cstdio>
#include<cctype>
#include<vector>
using namespace std;
struct edge
{int to,pre;
}edges[1000001];
int head[1000001],dfn[1000001],dfs_clock,tot;
int num;//BCC数量
int stack[1000001],top;//栈
vector<int>bcc[1000001];
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=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);add(x,y),add(y,x);}for(int i=1;i<=n;i++)//遍历n个点tarjan if(!dfn[i]){stack[top=1]=i;tarjan(i,i);}for(int i=1;i<=num;i++){printf("BCC#%d: ",i);for(int j=0;j<bcc[i].size();j++)printf("%d ",bcc[i][j]);printf("\n");}return 0;
}
边双连通分量 和 点双连通分量 的缩点
• 每个边双连通分量缩成一个点,再用原来的桥把他们连起来
• 点双联通分量因为一个割点可能包含在多个点双连通分量里面,所以我们将每个割点保留割点与其所在的点双连通分量连边即可。
有向图的弱连通与强连通
• 在有向图G=(V,E)中,如果对于任意两点u,v,存在一条从u到v或者从v到u的路径——弱联通
• 在有向图G=(V,E)中,如果对于任意两点u,v都互相可达——强联通
强连通分量
• 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路
径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。 • 如果有向图G的每两个顶点都强连通,称G是一个强连通图。
• 有向图的极大强连通子图,称为强连通分量(strongly connected components)。
Kosaraju算法
• 对原图进行一次dfs(任意起点)
• 在第一次形成的森林的每一颗树里,以第一次搜索出栈时间的逆序对反图进行dfs,这次搜索A能到达的点和A都在一个强连通分量里面
Tarjan算法
• Dfn[n]时间戳
• Low[n]他和他的子树里返祖边和横叉边能连到还没出栈的dfn最小的点
• 在dfs的时候维护一个栈第一次访问到某个点就将其加入到栈中,当一个点x的dfn[x] == low[x] 时,他就是这个强连通分量里面在搜索树中最高的点,将栈里点出栈直到x也出栈为止,这些点组成一个强连通分量。
代码:
void tarjan(int x)
{dfn[x]=low[x]=++cnt;stack[++top]=x;vis[x]=1;//x是否在栈里 for(int i=head[x];i;i=edge[i].next){int v=edge[i].v;if(!dfn[v]){tarjan(v);low[x]=min(low[x],low[y]);}else if(vis[v])low[x]=min(low[x],dfn[v]);if(dfn[x]==low[x])//是否是强连通分量最高的点 {ans++;//新强连通的标号 do{int cur=stack[top--];//栈顶的点 vis[cur]=false;num[cur]=ans;}while(x!=cur);}}}
第1节 连通性强连通、割点和桥(一)相关推荐
- 第1节 连通性强连通、割点和桥 例题
NC15707 可达性 题目: 给出一个 0 ≤ N ≤ 105 点数.0 ≤ M ≤ 105 边数的有向图, 输出一个尽可能小的点集,使得从这些点出发能够到达任意一点,如果有多个这样的集合, 输出这 ...
- 图论之tarjan真乃神人也,强连通分量,割点,桥,双连通他都会
先来%一下Robert Tarjan前辈 %%%%%%%%%%%%%%%%%% 然后是热情感谢下列并不止这些大佬的博客: 图连通性(一):Tarjan算法求解有向图强连通分量 图连通性(二):Tarj ...
- 有向图的强连通分量,割点与桥
有向图的强连通分量 1.Tarjan /* Tarjan算法 复杂度O(N+M) */ #include<iostream> #include<stdio.h> #includ ...
- 图论 —— 图的连通性 —— Tarjan 求割点与桥
[概念] 1.割点 1)割点:删除某点后,整个图变为不连通的两个部分的点 2)割点集合:在一个无向图中删除该集合中的所有点,能使原图变成互不相连的连通块的点的集合 3)点连通度:最小割点集合点数 如上 ...
- tarjan算法 (割点和桥)
最近刚学习了tarjan算法,发一篇博客写一下自己的心得和理解. 在了解割点和桥之前,我们先理解什么是双连通. 双连通和强连通分别是应用于无向图和有向图中的,那么在学习双连通之前,请自行学习求强连通分 ...
- 南大算法设计与分析课程OJ答案代码(5)--割点与桥和任务调度问题
问题 A: 割点与桥 时间限制: 1 Sec 内存限制: 5 MB 提交: 475 解决: 34 提交 状态 算法问答 题目描述 给出一个无向连通图,找到所有的割点和桥 输入 第一行:点的个数,如 ...
- 模板:割点、桥与双连通
文章目录 割点 代码 桥 点双连通分量 代码 边双连通分量 代码 割点 和强连通分量十分相似 分为树枝边.前向边和后向边 注意! if(x!=r&&low[to]>=dfn[x] ...
- 图的割点、桥和双连通分支的基本概念
点连通度与边连通度 回到正题,首先介绍下什么是图的边连通度和点连通度.一般来说,点连通度是指对应一个图G,对于所有点集U属于V(G),也就是V(G)的子集中,使得G-U要么是一个非连通图,要么就是一个 ...
- 快乐地打牢基础(5)——割点和桥
一.定义 割点集合: 在一个无向连通图中,如果有一个顶点集合V,删除顶点集合V以及与V中顶点相连(至少有一端在V中)的所有边之后,原图不连通,就称这个点为割点集合. 一个图的点连通度: 最小割点集合的 ...
最新文章
- 统计一个字符串中单词的个数
- python实现WordCount(第三次作业)
- mybatis实现反向工程
- 【图像处理】——Python实现几何变换(自定义+opencv库)
- js 跳转传递汉字参数
- 《冷眼看IT》读书笔记--IT将成为服务行业
- python 中gcd用法_Python中while语句的基本用法不了解一下嘛?
- picker从后台取数据
- mapper的更多细节,日志配置、核心文件的配置等
- 8uftp上传失败,6步解决8uftp上传失败问题
- 2020年深圳杯数学建模竞赛A题
- 【微信自动续费】委托代扣接口常见问题QA
- 借助rtcp实现NACK丢包重传
- 暴力破解带有密码的压缩文件
- 【Python-GUI开发】四 pyqt5 UI扁平化设计
- 要依赖于抽象,不要依赖于具体
- k8s的namespace资源一直terminating问题解决
- 小米应用市场隐私政策
- 三款好用的语音转文字软件,你知道几个?
- 核心技术及创新点怎么写
热门文章
- 打得了橄榄球大联盟,进得了麻省理工,无论是四肢还是头脑都同样发达,这才叫猛男!...
- php round 取余,PHP round() 函数
- 流量节省模式 Android,这三种方法让你节省更多手机上网流量
- linux的自定义input,linux键值到Android键值的转换与自定义
- vue html引入图片,vue引入图片的几种方式
- win7美化_Potplayer64位美化版,无棒子的tv推送
- code删除前两个_听说用python来批量删除说说也挺快乐的呢~
- jsoup 获取html中body内容_jsoup实现java抓取网页内容
- java 连接池连接mysql数据库需要哪些jar包_DBCP-基于Java8导入DBCP连接池所需JAR包并编写DBCPUtils工具类...
- Linux链接文件包括,Linux操作系统——系统各目录有什么作用、以及文件链接过程...