当前位置: 首页 > news >正文

20250818 割点 割边 点双总结

引子

这是一个引子 ^ _ ^

连通分量

首先,我们知道子图就是从一张图里选出几个点和几条边,如果子图里面的各个点互相连通,就叫连通子图,连通子图的点和边数量尽可能大就是极大连通子图,注意,是极大,我们把极大连通子图叫做连通分量,也叫连通块

所以一张图里连通分量的数量是有限的,并且唯一,下面来举个栗子:

1
2
3
4
5
6
7

以上图有两个连通分量,分别为{1,2,3,4,5}和{6,7}。

割点

在一张图里,去掉一个点,如果连通分量数量增加了,说明这个点是割点,也就是说这个点原来所处的连通分量不连通了,分裂成了更多的连通分量。

有一种蒻的不能再蒻的算法,也就是把每个点假设为割点,看把这个点去掉后连通分量是否增加了。当然,我们通常用tarjan算法来找割点。

实现

tarjan算法在dfs过程中动态维护dfn和low两个数组。其中low表示节点在不经过搜索树父节点情况下能到达的最小时间戳。

判断割点的核心条件:

  1. 对于非根节点u,若存在子节点v满足lowv≥dfnulow_v \geq dfn_ulowvdfnu,则u是割点。该条件表明删除u后,v所在子树无法通过其他路径回到u的祖先节点。
  2. 对于根节点,需要特殊处理:若其在搜索树中有两个及以上子节点,则为割点;否则不是割点。

证明思路:

  1. 当根节点只有一个子节点时,说明整个连通分量可以通过单次搜索遍历完成,删除根节点不会增加连通分量数量。
  2. 当根节点有多个子节点时,说明各子树之间没有其他连接路径,删除根节点将导致各子树相互隔离,从而增加连通分量数量。

这种判断方法确保了割点判定的正确性和高效性。

tarjan时间复杂度O(n+m)。

vector<int>E[20005];
int low[20005],dfn[20005],n,m,k;
bool cut[20005];
void tarjan(int x,int f){int s=0;k++;dfn[x]=low[x]=k;for(int i=0;i<E[x].size();i++){int v=E[x][i];if(!dfn[v]){tarjan(v,f);low[x]=min(low[x],low[v]);if(low[v]>=dfn[x]&&x!=f){cut[x]=1;}if(x==f){s++;}}else{low[x]=min(dfn[v],low[x]);}}if(x==f&&s>=2){cut[x]=1;}
}

割边

和割点同理,只是从去掉一个点变成了去掉一条边。

大致和割点都差不多,只是判断条件不一样,改成了lowv>dfnulow_v > dfn_ulowv>dfnu

时间复杂度当然相同。

实现

vector<int>E[155];
vector<edge>e;
int low[155],dfn[155],n,m,k;
void dfs(int x,int f){dfn[x]=low[x]=++k;for(int i=0;i<E[x].size();i++){int v=E[x][i];if(v!=f){if(!dfn[v]){dfs(v,x);low[x]=min(low[x],low[v]);if(low[v]>dfn[x]){e.push_back({min(x,v),max(x,v)});}}else{low[x]=min(dfn[v],low[x]);}}}
}

点双连通分量

任意删除一个点后仍保持连通的连通分量称为点双连通分量,简称点双

  • 任意两个点双之间至多有一个公共点,该点必为割点
  • 在搜索树中,每个点双的dfn的最小点必定是割点或根节点

只要用一个栈记录已访问顶点,当回溯到割点时提取对应的点双连通分量就行了。

int s[M],low[N],dfn[N],fir[N],nxt[M],to[M],idx,n,m,top,bcc;
vector<int>ans[N];
void tarjan(int u,int fa){int son=0;low[u]=dfn[u]=++idx;s[++top]=u;for(int i=fir[u];i;i=nxt[i]){int v=to[i];if(!dfn[v]){son++;tarjan(v,u);low[u]=min(low[u],low[v]);if(low[v]>=dfn[u]){bcc++;while(s[top + 1]!=v){ans[bcc].push_back(s[top--]);}ans[bcc].push_back(u);}}else if(v!=fa){low[u]=min(low[u],dfn[v]);}}if(fa==0&&son==0){ans[++bcc].push_back(u);}
}
http://www.dtcms.com/a/336974.html

相关文章:

  • 一个基于纯前端技术实现的五子棋游戏,无需后端服务,直接在浏览器中运行。
  • 数据挖掘 3.5 支持向量机——边界和正则化
  • 二分查找例题
  • 从基础到架构的六层知识体系
  • 进阶向:人物关系三元组,解锁人物关系网络的钥匙
  • 如何新建一个自己的虚拟环境
  • 有向无环图(Directed Acyclic Graph, DAG)介绍(环检测、DFS法、Kahn算法、)
  • 【Langchain系列三】GraphGPT——LangChain+NebulaGraph+llm构建智能图数据库问答系统
  • 15.三数之和
  • InfluxDB 开发工具链:IDE 插件与调试技巧(二)
  • 01.Linux小技巧
  • 从 UI 角度剖析蔬菜批发小程序的设计之道——仙盟创梦IDE
  • STRIDE威胁模型
  • IDE开发系列(1)基于QT的简易IDE框架设计
  • 【P38 6】OpenCV Python——图片的运算(算术运算、逻辑运算)加法add、subtract减法、乘法multiply、除法divide
  • 实践笔记-VSCode与IDE同步问题解决指南;程序总是进入中断服务程序。
  • 面试 TOP101 二叉树专题题解汇总Java版(BM23 —— BM41)
  • 深入解析StatefulSet与K8s服务管理
  • 集成电路学习:什么是Face Detection人脸检测
  • 多线程初阶-线程安全 (面试和工作的重点!!!)
  • Vue2篇——第六章 Vue 路由(VueRouter)全解析
  • Linux系统网络排查工具总结
  • org.apache.kafka.clients 和 org.springframework.kafka 的区别
  • kafka 发送消息有哪些模式?各自的应用场景是什么?
  • Elasticsearch全文检索中文分词:IK分词器详解与Docker环境集成
  • AI编程工具对决:Kilo vs Augment 开发Flutter俄罗斯方块游戏实战对比
  • 【AI论文】UI-Venus技术报告:借助强化微调(RFT)打造高性能用户界面(UI)代理
  • 手写Spring容器核心原理
  • 加密资产投资的六种策略:稳定币合规后的 Web3 投资和 RWA
  • 杂记 05