B3610 [图论与代数结构 801] 无向图的块 题解

B3610 [图论与代数结构 801] 无向图的块 题解

2023 2023 2023,再见。 2024 2024 2024,你好!

解法

其实就是统计点双连通分量的个数。需要注意的是,孤立点在这里不被看作块。本文使用 tarjan 算法来解决这道题。

概念明晰

  • 时间戳:这里记为 d f n i dfn_i dfni,表示第一次深度优先搜索到节点 i i i 的时间。时间 t i m e ∈ N + time \in \mathbb{N}^+ timeN+ 且随这搜索依次递增。
  • 搜索树:从选定的节点出发的深搜,每个节点仅搜索一次,把所有搜索路径组成一颗树,称为搜索树。如果给定的图不是一整个连通图,则称为搜索森林。
  • 追溯值:这里记为 l o w i low_i lowi,表示节点 i i i 最多经过一条返祖边能走到搜索树中以 i i i 的子树中的节点的最小 d f n dfn dfn 为多少(简洁的定义出自东灯的博客)。
  • 割点:对于一个无向图,如果把一个点删除后这个图的极大连通分量数增加了,那么这个点就是这个图的割点。

追溯值的计算

首先根据定义, l o w i low_i lowi 的初始值应赋为 d f n i dfn_i dfni。现在考虑怎么进一步更新 l o w i low_i lowi

  • 如果在搜索树上 i i i j j j 的父节点,则 l o w i = min ⁡ ( l o w i , l o w j ) low_i = \min(low_i,low_j) lowi=min(lowi,lowj)
  • 如果从 i i i j j j 的连边不是搜索树上的边,则 l o w i = min ⁡ ( l o w i , d f n j ) low_i= \min(low_i,dfn_j) lowi=min(lowi,dfnj)

割点的判定方法

定义搜索树中节点 i i i 的子树为 s o n i son_i soni

  • 如果 i i i 不是搜索树的根,则当 ∃ d f n i ≤ l o w j , j ∈ s o n i \exists dfn_i \le low_j,j \in son_i dfnilowj,jsoni 时, i i i 是割点。
  • 如果 i i i 是搜索树的根,则当有两个不同的 j j j 满足上述条件时, i i i 是割点。

判定方法的证明

如果 d f n i ≤ l o w j dfn_i \le low_j dfnilowj,则证明从 j ∈ s o n i j \in son_i jsoni 出发,不经过点 i i i 无论如何也不能到达 i i i 的祖先。所以如果把 i i i 删去,则 s o n i son_i soni 就会与原图分离。

代码

#include<bits/stdc++.h>
using namespace std;
#define Getchar() p1==p2 and (p2=(p1=Inf)+fread(Inf,1,1<<7,stdin),p1==p2)?EOF:*p1++
#define Putchar(c) p3==p4 and (fwrite(Ouf,1,1<<7,stdout),p3=Ouf),*p3++=c
char Inf[1<<7],Ouf[1<<7],*p1,*p2,*p3=Ouf,*p4=Ouf+(1<<7);
inline void read(int &x,char c=Getchar())
{bool f=c!='-';x=0;while(c<48 or c>57) c=Getchar(),f&=c!='-';while(c>=48 and c<=57) x=(x<<3)+(x<<1)+(c^48),c=Getchar();x=f?x:-x;
}
inline void write(int x)
{if(x<0) Putchar('-'),x=-x;if(x>=10) write(x/10),x%=10;Putchar(x^48);
}
struct my_stack
{int top,a[500010];inline int size(){return top;}inline int &operator[](const int &x){return a[x];}inline int back(){return a[top];}inline void push_back(const int &x){a[++top]=x;}inline void pop_back(){top--;}inline void clear(){top=0;}
};
my_stack v;
int n,m,head[500010],cnt,dfn[500010],low[500010],times,belong[500010],tot;
vector<int> ans[500010];
struct edge
{int to,next;
};
edge e[4000010];
inline void add(const int &x,const int &y) noexcept
{e[++cnt].to=y,e[cnt].next=head[x],head[x]=cnt;
}
inline void tarjan(const int &pos,const int &fa)
{int son=0;dfn[pos]=low[pos]=++times,v.push_back(pos);for(int i=head[pos];i;i=e[i].next)if(!dfn[e[i].to]){son++,tarjan(e[i].to,pos),low[pos]=min(low[pos],low[e[i].to]);if(low[e[i].to]>=dfn[pos]){tot++;while(v[v.top+1]!=e[i].to) ans[tot].push_back(v.back()),v.pop_back();ans[tot].push_back(pos);}}else if(e[i].to!=fa) low[pos]=min(low[pos],dfn[e[i].to]);
}
int main()
{read(n),read(m);for(int i=1,x,y;i<=m;i++) read(x),read(y),add(x,y),add(y,x);for(int i=1;i<=n;i++) if(!dfn[i]) v.clear(),tarjan(i,0);for(int i=1;i<=tot;i++) std::sort(ans[i].begin(),ans[i].end());std::sort(ans+1,ans+tot+1,[](std::vector<int> &lhs,std::vector<int> &rhs){for(int i=0;i<std::min(lhs.size(),rhs.size());i++) if(lhs[i]!=rhs[i]) return lhs[i]<rhs[i];return lhs.size()<rhs.size();});write(tot),Putchar('\n');for(int i=1;i<=tot;i++,Putchar('\n')){for(int j=0;j<ans[i].size();j++) write(ans[i][j]),Putchar(' ');}fwrite(Ouf,1,p3-Ouf,stdout),fflush(stdout);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/588706.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习:贝叶斯估计在新闻分类任务中的应用

文章摘要 随着互联网的普及和发展&#xff0c;大量的新闻信息涌入我们的生活。然而&#xff0c;这些新闻信息的质量参差不齐&#xff0c;有些甚至包含虚假或误导性的内容。因此&#xff0c;对新闻进行有效的分类和筛选&#xff0c;以便用户能够快速获取真实、有价值的信息&…

【完整思路】2023 年中国高校大数据挑战赛 赛题 B DNA 存储中的序列聚类与比对

2023 年中国高校大数据挑战赛 赛题 B DNA 存储中的序列聚类与比对 任务 1.错误率和拷贝数分析&#xff1a;分析“train_reads.txt”和“train_reference.txt”数据集中的错误率&#xff08;插入、删除、替换、链断裂&#xff09;和序列拷贝数。 2.聚类模型开发&#xff1a;开发…

Unity坦克大战开发全流程——结束场景——失败界面

结束场景——失败界面 在玩家类中重写死亡函数 在beginPanel中锁定鼠标

Redis 分布式锁总结

在一个分布式系统中,由于涉及到多个实例同时对同一个资源加锁的问题,像传统的synchronized、ReentrantLock等单进程情况加锁的api就不再适用,需要使用分布式锁来保证多服务实例之间加锁的安全性。常见的分布式锁的实现方式有zookeeper和redis等。而由于redis分布式锁相对于比…

搭建普罗米修斯Prometheus,并监控MySQL

1.简介 prometheus是一种时间序列的数据库&#xff0c;适合应用于监控以及告警&#xff0c;但是不适合100%的准确计费&#xff0c;因为采集的数据不一定很准确&#xff0c;主要是作为监控以及收集内存、CPU、硬盘的数据。 Prometheus生态系统由多个组件组成&#xff0c;其中许…

积水监测识别摄像机

积水监测识别摄像机是一种利用摄像技术来监测和识别道路、桥梁、隧道等区域积水情况的设备&#xff0c;它可以有效地提供实时的积水监测信息&#xff0c;帮助交通部门和相关单位及时采取应对措施&#xff0c;确保道路交通的畅通和人员安全。 积水监测识别摄像机通过安装在适当位…

STM32F407ZGT6定时器(学习笔记二)

STM32F407ZGT6定时器&#xff08;学习笔记一&#xff09;-CSDN博客这篇文章中已经对前三种定时器的使用进行了介绍&#xff0c;本篇文章将介绍&#xff08;1&#xff09;输入捕获之计算方波时长&#xff0c;&#xff08;2&#xff09;输入捕获之编码器模式。 高级定时器和通用定…

【深入之Java进阶篇】fastjson的反序列化漏洞(详解总结)

✔️ fastjson的反序列化漏 1️⃣典型解析2️⃣拓展知识仓1️⃣AutoType2️⃣AutoType 有何错?3️⃣ 绕过checkAutotype&#xff0c;黑客与fastjson的博弈4️⃣autoType不开启也能被攻击?5️⃣利用异常进行攻击6️⃣AutoType 安全模式? 1️⃣典型解析 当我们使用fastjson进行…

mllib可扩展学习库java api使用

mllib可扩展学习库java api是使用Apache Spark构建的机器学习库&#xff0c;包括分类&#xff0c;聚类&#xff0c;特征提取和预处理等功能。本文将从以下几个方面详细介绍如何使用mllib可扩展学习库java api。 一、数据预处理 数据预处理是机器学习的重要步骤之一&#xff0…

2023.12.28 Python高级-正则表达式

目录 re正则表达式,一种专门用来匹配目标字符串的规则 re.match(),从头匹配一个,无则none re.search(), 不从头匹配返回一个,无则none re.findall(), 不从头匹配,用list返回所有 re分组 re匹配修饰符 re贪婪非贪婪 re切割和替换 re正则表达式,一种专门用来匹配目标字符串…

linux的页缓存page cache

目录 如何查看系统的 Page Cache&#xff1f; 为什么 Linux 不把 Page Cache 称为 block cache&#xff1f; Page Cache 的优劣势 Page Cache 的优势 加快数据访问 减少 IO 次数&#xff0c;提高系统磁盘 I/O 吞吐量 Page Cache 的劣势 由于我们开发的程序要运行的话一般…

redis—List列表

目录 前言 1.常见命令 2.使用场景 前言 列表类型是用来存储多个有序的字符串&#xff0c;如图2-19所示&#xff0c;a、b、C、d、e五个元素从左到右组成 了一个有序的列表&#xff0c;列表中的每个字符串称为元素(element) &#xff0c;一个列表最多可以存储2^32 - 1 个元素…

功能开发 -- 向埃隆·马斯克学习任务分解

文章目录 马斯克的任务分解软件开发的任务分解可执行的最小单位任务小结 马斯克的任务分解 我们都知道埃隆马斯克&#xff08;Elon Musk&#xff09;&#xff0c;他既是电动汽车公司特斯拉&#xff08;Tesla&#xff09;的创始人&#xff0c;同时还创建了太空探索公司 SpaceX。…

李宏毅 自然语言处理(Voice Conversion) 笔记

前一章笔记&#xff1a;李宏毅 自然语言处理&#xff08;Speech Recognition&#xff09; 笔记 引入 什么是voice conversion&#xff1f; 输入一段声音&#xff0c;输出另一段声音&#xff0c;我们希望这两端声音&#xff1a;内容一样&#xff0c;其他方面不一样&#xff08…

[设计模式 Go实现] 创建型~建造者模式

建造者模式&#xff08;Builder Pattern&#xff09;使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。 一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。 代码实…

每日一题——LeetCode977

方法一 个人方法&#xff1a; 以示例1为例&#xff1a;把[-4,-1,0,3,10] 中n<0的元素拆分出来&#xff0c;把他们的平方从小到大放入arr数组&#xff0c;则arr[0,1,16] ,那数组就还剩[3,10] 对于剩下的元素&#xff0c;看arr里面有没有比他们平方更小的元素先放入res数组&…

vue3-12

需求是用户如果登录了&#xff0c;可以访问主页&#xff0c;如果没有登录&#xff0c;则不能访问主页&#xff0c;随后跳转到登录界面&#xff0c;让用户登录 实现思路&#xff0c;在用户登录之前做一个检查&#xff0c;如果登录了&#xff0c;则token是存在的&#xff0c;则放…

回顾2023,我的编程学习之旅

文章目录 前言我与C语言初识C语言简易扫雷游戏二进制的美妙神奇的指针强大的结构体灵活的动态内存管理总结 我与竞赛我与CSDN结语 前言 6月8号高考结束了&#xff0c;虽然还没有出分&#xff0c;但是也大致规划好自己想学什么专业了&#xff0c;没错就是计算机&#xff0c;出分…

RedisTemplate自增时保证原子性的lua脚本限制接口请求频率

场景&#xff1a;限制请求后端接口的频率&#xff0c;例如1秒钟只能请求次数不能超过10次&#xff0c;通常的写法是&#xff1a; 1.先去从redis里面拿到当前请求次数 2.判断当前次数是否大于或等于限制次数 3.当前请求次数小于限制次数时进行自增 这三步在请求不是很密集的时…

yarn run dev运行ant design pro项目报错-‘max‘ 不是内部或外部命令

运行ant design pro项目报错&#xff1a; >>yarn run dev yarn run v1.22.19 $ npm run start:dev > ant-design-pro6.0.0-beta.1 start:dev > cross-env REACT_APP_ENVdev MOCKnone UMI_ENVdev max dev max 不是内部或外部命令&#xff0c;也不是可运行的程序 …