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

无向图联通分量总结

无向图联通分量总结

点双联通分量

定义

点集中任意两点间具有点不重复的路径

删去 \(u , v\) 以外的某点后 \(u , v\) 之间仍然联通

割点

定义:删除该点后使得图中极大联通分量数量增加的点

特性:一个点从属于两个点双是该点成为割点的充要条件,且两个点双最多共用一个割点

割点的求解

对该图建立 \(dfs\) 树,经过的边称树边,否则称返祖边,维护两个数组 \(dfn_i\)\(low_i\),分别保存节点 \(i\)\(dfs\) 序和通过返祖边能够返回到的最早位置,如果节点 \(u\) 的子节点无法通过返祖边返回到早于节点 \(u\) 的节点,则删除节点 \(u\) 后该图将不再联通,即 \(u\) 是割点
特别的,没有任何点可以返回根节点的上方,需统计其子节点数量判断

割点模板题

#include<iostream>
#include<set>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int N=2e4+5;
const int M=1e5+5;
int n,m,head[N],nxt[M<<1],to[M<<1],cnt=0,dfn[N],low[N],idx=0;
set<int>ans;
void add(int u,int v)
{to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
}
void Tarjan(int u,int fa)
{dfn[u]=low[u]=++idx;int son=0;for(int i=head[u];i;i=nxt[i]){int v=to[i];if(v==fa) continue;if(dfn[v])//u->v是一条返祖边low[u]=min(low[u],dfn[v]);//在求解割点时不能用low[v]更新low[u],否则无法满足“点不重复的路径”else{son++;Tarjan(v,u);low[u]=min(low[u],low[v]);if(fa!=0&&low[v]>=dfn[u])//u的子节点无法通过返祖边返回比u更早的节点ans.insert(u);}}if(fa==0&&son>=2)//根节点是割点ans.insert(u);
}
int main()
{IOS;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);//题目不保证联通cout<<ans.size()<<'\n';for(set<int>::iterator it=ans.begin();it!=ans.end();it++)cout<<*it<<' ';return 0;
}

点双联通分量的求解

由于是按照 \(dfs\) 序遍历,因此遇到割点时,只需要取出已经走过的点,用栈倒序存储

点双联通分量模板题

#include<iostream>
#include<stack>
#include<vector>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int N=5e5+5;
const int M=2e6+5;
int n,m,head[N],nxt[M<<1],to[M<<1],cnt=0,dfn[N],low[N],idx=0,bcccnt=0;
stack<int>stk;
vector<int>ans[N];
void add(int u,int v)
{to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
}
void Tarjan(int u,int fa)
{dfn[u]=low[u]=idx++;stk.push(u);for(int i=head[u];i;i=nxt[i]){int v=to[i];if(v==fa) continue;if(dfn[v]) low[u]=min(low[u],dfn[v]);else{Tarjan(v,u);low[u]=min(low[u],low[v]);if(low[v]>=dfn[u])//找到一个割点{bcccnt++;while(stk.top()!=v){ans[bcccnt].push_back(stk.top());stk.pop();}ans[bcccnt].push_back(v),stk.pop();ans[bcccnt].push_back(u);//割点可从属于多个点双,所以仍保留在栈内}}}if(fa==0&&!head[u])//孤立点也算一个点双ans[++bcccnt].push_back(u);
}
int main()
{IOS;cin>>n>>m;for(int i=1;i<=m;i++){int u,v;cin>>u>>v;if(u!=v)//注意自环add(u,v),add(v,u);}for(int i=1;i<=n;i++)if(!dfn[i]) Tarjan(i,0);cout<<bcccnt<<'\n';for(int i=1;i<=bcccnt;i++){cout<<ans[i].size()<<' ';for(vector<int>::iterator it=ans[i].begin();it!=ans[i].end();it++)cout<<*it<<' ';cout<<'\n';}return 0;
}

边双联通分量

定义

点集中任意两点具有边不重复的路径

删去任意一条边后,该子图仍然联通

特性

一个点只可能从属于一个边双

割边

定义:删除该边后使得图中极大联通分量数量增加的边

割边的求解

内容大体和求解割点相同,区别在于:

  • 对于返祖边 \(u->v\) ,可以使用 \(low_v\) 更新 \(low_u\) ,不会违背“边不重复”的原则

  • 重边需单独考虑,\(u,v\) 之间有重边的情况下删去一条不影响二者间的联通性

割边模板题

#include<iostream>
#include<vector>
#include<utility>
#include<algorithm>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int N=155;
const int M=5005;
int n,m,head[N],nxt[M<<1],to[M<<1],cnt=0,dfn[N],low[N],idx=0;
vector<pair<int,int>>ans;
void add(int u,int v)
{to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
}
void Tarjan(int u,int fa)
{dfn[u]=low[u]=++idx;int cnt=0;for(int i=head[u];i;i=nxt[i]){int v=to[i];if(v==fa)//注意重边{cnt++;if(cnt==1) continue;}if(!dfn[v]) Tarjan(v,u),low[u]=min(low[u],low[v]);elselow[u]=min(low[u],low[v]);//区别if(low[v]>dfn[u])//注意此处不可取等,相等时删去u,v之间的连边没有影响ans.push_back({min(u,v),max(v,u)});}
}
bool cmp(pair<int,int>x,pair<int,int>y)
{if(x.first==y.first) return x.second<y.second;return x.first<y.first;
}
int main()
{IOS;cin>>n>>m;for(int i=1;i<=m;i++){int u,v;cin>>u>>v;add(u,v),add(v,u);}Tarjan(1,0);sort(ans.begin(),ans.end(),cmp);for(vector<pair<int,int>>::iterator it=ans.begin();it!=ans.end();it++)cout<<(*it).first<<' '<<(*it).second<<'\n';return 0;
}
http://www.sczhlp.com/news/2220/

相关文章:

  • Redis命令:列表模糊删除详解
  • 工控机使用SysVinit 启动脚本
  • 【汽车科普】汽车点火开关的四个档位:LOCK、ACC、ON(IGN)、START
  • 代码管理平台选择指南
  • LED灯闪烁
  • 31、制作菜单
  • 博客园书写格式示例
  • Windows nodejs多版本安装
  • springboot当中ConfigurationProperties注解作用跟数据库存入有啥区别
  • mysql导出表字段
  • 图像生成-Conditional Flow Matching-12 - jack
  • 从技术到合规:璞华科技与传神语联合作完成大模型数据资产入表,「璞华易表」赋能 AI 资产化实践
  • SQL Server 中 CROSS APPLY 使用教程
  • 联想拯救者电脑睡眠模式关闭呼吸灯
  • centos系统清理docker日志文件
  • go 语言特性
  • electron-egg实现全量更新和增量更新(下)
  • 【刷题笔记】P2824 [HEOI2016/TJOI2016] 排序
  • BT134-600-ASEMI双向可控硅BT134-600
  • JUC学习-22-源码解读(线程池如何创建线程)
  • 以dotnet为例,创建软路由
  • MyEMS开源能源管理系统核心代码解读026
  • 面试官说:在区块链交易所的高并发环境下,不依靠数据库事务保持一致性,对大的事务进行拆分,比如用对账系统保证一致性,最终数据库仅仅是持久化的功能。如何理解这种思想 - Charlie
  • 范畴论基础概念和 Yoneda Lemma 定理
  • API分享:利用API接口实现批量获取淘宝商品详情的主图视频
  • 点亮LED灯
  • 【汽车电子】一个系统
  • AtCoder Beginner Contest 416 - F - Paint Tree 2 题解
  • 认识Arduino 电路基础知识
  • 基于Java+Springboot+Vue开发的网上服装销售管理系统源码+运行步骤