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

【图论】无向图连通性(tarjan算法)

割边:dfn[u]<low[v]

割点:dfn[u]<=low[v] (若为根节点,要有两个v这样的点)

一.知识点:

1.连通

在图论中,连通性是指一个无向图中的任意两个顶点之间存在路径。如果对于图中的任意两个顶点 u 和 v,存在一条路径从 u 到 v,那么图被称为连通图。如果图不是连通的,那么它可以被分为多个连通分量,每个连通分量都是一个连通子图。

2.割点:

割点(Cut Vertex),也称为关节点或割顶,是指在无向图中,如果移除该顶点及其相连的边,会导致图不再连通,那么该顶点就被称为割点。

3.割边:

割边(Cut Edge),也称为,是指在无向图中,如果移除该边,会导致图不再连通,那么该边就被称为割边。

割边在图中起到了连接不同连通分量的作用,其移除会导致图的连通性发生变化。

 4.tarjan算法:(选择性阅读)

 Tarjan算法是一种用于寻找有向图中强连通分量(Strongly Connected Components,简称SCC)的算法,由Robert Tarjan在1972年提出。强连通分量是指在有向图中,任意两个顶点之间存在双向路径。

Tarjan算法使用深度优先搜索(DFS)来遍历图,并通过维护一个栈和一些辅助数据结构来识别强连通分量。算法的基本思想是通过DFS遍历图中的每个顶点,并为每个顶点记录其访问次序(Discovery Time)和能够回溯到的最早的祖先顶点(Lowest Ancestor)。通过这些信息,可以识别出具有相同祖先的顶点集合,即一个强连通分量。

Tarjan算法的步骤如下:

  1. 对图中的每个顶点进行深度优先搜索(DFS)遍历。
  2. 在DFS遍历的过程中,为每个顶点记录其访问次序和最早祖先顶点。
  3. 将已访问的顶点入栈。
  4. 当DFS遍历回溯到一个顶点时,检查该顶点的最早祖先顶点。如果最早祖先顶点是自身,则将栈中的顶点弹出,并将这些顶点构成一个强连通分量。
  5. 重复步骤3和步骤4,直到遍历完所有的顶点。

Tarjan算法的时间复杂度为O(V+E),其中V是顶点数,E是边数。它是一种高效的算法,常被用于解决与强连通分量相关的问题,如图的缩点、强连通分量的数量和结构等。

总之,Tarjan算法是一种用于寻找有向图中强连通分量的算法,通过DFS遍历和栈的运用,可以高效地找到图中的所有强连通分量。


二.讲解 

在此之前,先介绍两个数组;

int dfn[];里面存放访问顺序(时间戳);

int low[];里面存放追溯值(即祖先节点最小的dfn)

(1)割边

tarjan提出:(证明可以自行百度)

当dfn[u]<low[v]时,连接这两条点的边为割边(重边要特殊处理,后面介绍)

(2)割点

tarjan提出:(证明可以自行百度)

当dfn[u]<=low[v]时,u这个点为割点(若为根节点,要有两个v这样符合条件的点)


三.割边

(1)题目

题目描述:

找出割边

输入:

第一行输入两个整数n和m,表示点和边的个数。

第i(2<=i<=2+m)行,每行输出两个数字,表示一条边的两个点。

输出:

割边

样例输入:

6 7
1 2
1 3
2 4 
2 5
3 4
4 5
4 6

样例输出:

4---6

(2)初代码 

/*
6 7
1 2
1 3
2 4 
2 5
3 4
4 5
4 6
*/#include<bits/stdc++.h>
#define maxn 100005
using namespace std;
int n,m;
struct Edge{int u,v,next;
}edge[maxn<<1];
int cnt,head[maxn];
void add(int u,int v){edge[++cnt]=(Edge){u,v,head[u]}; head[u]=cnt;
}
int num,dfn[maxn],low[maxn];
void tarjan(int u,int fa){dfn[u]=low[u]=++num;for(int i=head[u];i;i=edge[i].next){int v=edge[i].v;if(v==fa) continue;if(dfn[v]==0){tarjan(v,u);low[u]=min(low[u],low[v]);if(dfn[u]<low[v]){ //割边条件 ,若>则表示v不止和u相连 cout<<u<<"----"<<v<<endl; }}else{low[u]=min(low[u],dfn[v]);}}
}
int main(){scanf("%d%d",&n,&m);int u,v;for(int i=1;i<=m;i++){scanf("%d%d",&u,&v);add(u,v); add(v,u);}tarjan(1,0);return 0;
}

(3)bug与解答

1.若这张图有多个连通分量怎么办?

答:遍历即可

	for(int i=1;i<=n;i++){if(dfn[i]==0)  tarjan(1,0);}

2.若有重边怎么办?结果显然不对。

答:只continue,第二次让这段代码运行

然后就无法满足 dfn[u]<low[v]条件了

		if(v==fa){k++; //防止重边 if(k==1) continue;} 

(4)最终代码

/*
6 7
1 2
1 3
2 4 
2 5
3 4
4 5
4 6
*/#include<bits/stdc++.h>
#define maxn 100005
using namespace std;
int n,m;
struct Edge{int u,v,next;
}edge[maxn<<1];
int cnt,head[maxn];
void add(int u,int v){edge[++cnt]=(Edge){u,v,head[u]}; head[u]=cnt;
}
int num,dfn[maxn],low[maxn];
void tarjan(int u,int fa){int k=0;dfn[u]=low[u]=++num;for(int i=head[u];i;i=edge[i].next){int v=edge[i].v;if(v==fa){k++; //防止重边 if(k==1) continue;} if(dfn[v]==0){tarjan(v,u);low[u]=min(low[u],low[v]);if(dfn[u]<low[v]){ //割边条件 ,若>则表示v不止和u相连 cout<<u<<"---"<<v<<endl; }}else{low[u]=min(low[u],dfn[v]);}}
}
int main(){scanf("%d%d",&n,&m);int u,v;for(int i=1;i<=m;i++){scanf("%d%d",&u,&v);add(u,v); add(v,u);}//防止本来就有不连通的 for(int i=1;i<=n;i++){if(dfn[i]==0)  tarjan(1,0);}return 0;
}

四.割点

其实只是微改动一下即可。其次就是可以优化一下。函数传参只需要传u,无需判断是否为父节点。因为不会影响结果。(自行参考代码推理)

再次强调:若为根节点,要有两个v这样的点!

参考代码:

/*
6 7
1 2
1 3
2 4 
2 5
3 4
4 5
4 6
*/#include<bits/stdc++.h>
#define maxn 100005
using namespace std;
int n,m;
struct Edge{int u,v,next;
}edge[maxn<<1];
int cnt,head[maxn];
void add(int u,int v){edge[++cnt]=(Edge){u,v,head[u]}; head[u]=cnt;
}
int num,dfn[maxn],low[maxn],root;
void tarjan(int u){dfn[u]=low[u]=++num;int flag=0;for(int i=head[u];i;i=edge[i].next){int v=edge[i].v;if(dfn[v]==0){tarjan(v);low[u]=min(low[u],low[v]);if(dfn[u]<=low[v]){ //割点条件 if(u!=root || flag>1) cout<<u<<" ";}}else{low[u]=min(low[u],dfn[v]);}}
}
int main(){scanf("%d%d",&n,&m);int u,v;for(int i=1;i<=m;i++){scanf("%d%d",&u,&v);add(u,v); add(v,u);}//防止本来就有不连通的 for(int i=1;i<=n;i++){if(dfn[i]==0){root=i;tarjan(i);} }return 0;
}

相关文章:

【图论】无向图连通性(tarjan算法)

割边&#xff1a;dfn[u]<low[v] 割点&#xff1a;dfn[u]<low[v] (若为根节点&#xff0c;要有两个v这样的点) 一.知识点&#xff1a; 1.连通&#xff1a; 在图论中&#xff0c;连通性是指一个无向图中的任意两个顶点之间存在路径。如果对于图中的任意两个顶点 u 和 v&…...

Docker安装

Docker实践 yum安装 YUM源可以使用官方YUM源、清华大学开源镜像站配置YUM源&#xff0c;也可以使用阿里云开源镜像站提供的YUM源&#xff0c;建议选择使用阿里云开源镜像站提供的YUM源&#xff0c;原因速度快。 地址: https://developer.aliyun.com/mirror/ 我们安装ce版 …...

06. 计数原理

6. 计数原理 6.1 分类加法计数原理与分步乘法计数原理 分类加法计数原理定义 完成一件事&#xff0c;有 n n n 类办法&#xff0c;在第1类办法中有 m 1 m_1 m1​ 种不同的方法&#xff0c;在第2类办法中有 m 2 m_2 m2​ 种不同的方法&#xff0c;…&#xff0c;在第 n n…...

计算机网络基础(静态路由,动态路由,公网IP,私网IP,NAT技术)

文章目录 一&#xff1a;静态路由和动态路由二&#xff1a;静态路由的配置路由信息的方式演示三&#xff1a;默认路由四&#xff1a;公网IP和私网IP和NAT技术的基本理解 一&#xff1a;静态路由和动态路由 在说静态路由和动态路由前&#xff0c;我们需要来了解一下&#xff0…...

CGAL 点云Alpha-Shape曲面重建算法

文章目录 一、简介二、相关参数三、实现代码四、实现效果参考资料一、简介 在数学上, a l p h a − s h a p e alpha-shape a...

Java 文件过滤器FileFilter | 按条件筛选文件

文章目录 一、概述1.1 何时会用到文件过滤器1.2 工作流程1.3 常用的接口和类1.4 文件过滤器的作用 二、按文件属性过滤2.1 按前缀或后缀过滤文件名2.2 按文件大小过滤 三、按文件内容过滤3.1 文本文件过滤器3.1.1 根据关键字过滤文件内容3.1.2 使用正则表达式过滤文件内容 3.2 …...

python格式化地址信息

背景 最近在折腾一个好玩的库&#xff0c;capa 实现地址的格式化输出。我看的教程是这样的&#xff1a; location_str ["徐汇区虹漕路461号58号楼5楼", "泉州市洛江区万安塘西工业区"] import cpca df cpca.transform(location_str) df在正式的运行代码…...

k8s1.26.6 安装gitlab

Gitlab官方提供了 Helm 的方式在 Kubernetes 集群中来快速安装&#xff0c;但是在使用的过程中发现 Helm 提供的 Chart 包中有很多其他额外的配置&#xff0c;所以我们这里使用自定义的方式来安装&#xff0c;也就是自己来定义一些资源清单文件。 Gitlab主要涉及到3个应用&…...

C5.0决策树建立个人信用风险评估模型

通过构建自动化的信用评分模型&#xff0c;以在线方式进行即时的信贷审批能够为银行节约很多人工成本。本案例&#xff0c;我们将使用C5.0决策树算法建立一个简单的个人信用风险评估模型。 导入类库 读取数据 #创建编码所用的数据字典 col_dicts{} #要编码的属性集 cols [che…...

【k8s集群部署】使用containerd运行时部署kubernetes集群(V1.27版本)

【k8s集群部署】使用containerd运行时部署kubernetes集群(V1.27版本) 一、本次实践介绍1.1 环境规划介绍1.2 本次实践简介二、三台主机基础环境配置2.1 主机配置工作2.2 关闭防火墙和selinux2.3 关闭swap2.4 清空iptables2.5 配置时间同步2.6 修改内核参数2.7 配置hosts文件三…...

网络安全进阶学习第八课——信息收集

文章目录 一、什么是信息收集&#xff1f;二、信息收集的原则三、信息收集的分类1.主动信息收集2.被动信息收集 四、资产探测1、Whois查询#常用网站&#xff1a; 2、备案信息查询#常用网站&#xff1a; 3、DNS查询#常用网站&#xff1a; 4、子域名收集#常用网站&#xff1a;#常…...

Spring Data Elasticsearch - 在Spring应用中操作Elasticsearch数据库

Spring Data Elasticsearch 文章目录 Spring Data Elasticsearch1. 定义文档映射实体类2. Repository3. ElasticsearchRestTemplate3.1 查询相关特性3.1.1 过滤3.1.2 排序3.1.3 自定义分词器 3.2 高级查询 4. 索引管理4.1 创建索引4.2 检索索引4.3 修改映射4.4 删除索引 5. 异常…...

图论-简明导读

计算机图论是计算机科学中的一个重要分支&#xff0c;它主要研究图的性质和结构&#xff0c;以及如何在计算机上有效地存储、处理和操作这些图。本文将总结计算机图论的核心知识点。 一、基本概念 计算机图论中的基本概念包括图、节点、边等。图是由节点和边构成的数据结构&am…...

记一次 .NET 某物流API系统 CPU爆高分析

一&#xff1a;背景 1. 讲故事 前段时间有位朋友找到我&#xff0c;说他程序CPU直接被打满了&#xff0c;让我帮忙看下怎么回事&#xff0c;截图如下&#xff1a; 看了下是两个相同的程序&#xff0c;既然被打满了那就抓一个 dump 看看到底咋回事。 二&#xff1a;为什么会打…...

【Docker】Docker安装Kibana服务_Docker+Elasticsearch+Kibana

文章目录 1. 什么是Kibana2. Docker安装Kibana2.1. 前提2.2. 安装Kibana 点击跳转&#xff1a;Docker安装MySQL、Redis、RabbitMQ、Elasticsearch、Nacos等常见服务全套&#xff08;质量有保证&#xff0c;内容详情&#xff09; 1. 什么是Kibana Kibana 是一款适用于Elasticse…...

前端面试题-VUE

1. 对于MVVM的理解 MVVM 是 Model-View-ViewModel 的缩写Model 代表数据模型&#xff0c;也可以在 Model 中定义数据修改和操作的业务逻辑。View 代表 UI 组件&#xff0c;它负责将数据模型转化成 UI 展现出来。ViewModel 监听模型数据的改变和控制视图⾏为、处理⽤户交互&…...

Linux嵌入式平台安全启动理解介绍

一、意义 安全启动可以防止未授权的或是进行恶意篡改的软件在系统上运行,是系统安全的保护石,每一级的前一个镜像会对该镜像进行校验。 1.1 安全启动原理介绍 通过数字签名进行镜像完整性验证(使用到非对称加密算法和哈希算法) 签名过程: raw_image--->use ha…...

安全学习DAY09_加密逆向,特征识别

算法逆向&加密算法分类&#xff0c;特征识别 文章目录 算法逆向&加密算法分类&#xff0c;特征识别算法概念&#xff0c;分类单向散列加密 - MD5对称加密 - AES非对称加密 - RSA 常见加密算法识别特征&#xff0c;解密特点MD5密文特点BASE64编码特点AES、DES特点RSA密文…...

原型模式(Prototype)

原型模式是一种创建型设计模式&#xff0c;使调用方能够复制已有对象&#xff0c;而又无需使代码依赖它们所属的类。当有一个类的实例&#xff08;原型&#xff09;&#xff0c;并且想通过复制原型来创建新对象时&#xff0c;通常会使用原型模式。 The Prototype pattern is g…...

深度学习之用PyTorch实现线性回归

代码 # 调用库 import torch# 数据准备 x_data torch.Tensor([[1.0], [2.0], [3.0]]) # 训练集输入值 y_data torch.Tensor([[2.0], [4.0], [6.0]]) # 训练集输出值# 定义线性回归模型 class LinearModel(torch.nn.Module):def __init__(self):super(LinearModel, self)._…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

MFC 抛体运动模拟:常见问题解决与界面美化

在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...

MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用

文章目录 一、背景知识&#xff1a;什么是 B-Tree 和 BTree&#xff1f; B-Tree&#xff08;平衡多路查找树&#xff09; BTree&#xff08;B-Tree 的变种&#xff09; 二、结构对比&#xff1a;一张图看懂 三、为什么 MySQL InnoDB 选择 BTree&#xff1f; 1. 范围查询更快 2…...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storms…...

抽象类和接口(全)

一、抽象类 1.概念&#xff1a;如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象&#xff0c;这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法&#xff0c;包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中&#xff0c;⼀个类如果被 abs…...

【C++】纯虚函数类外可以写实现吗?

1. 答案 先说答案&#xff0c;可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...

DiscuzX3.5发帖json api

参考文章&#xff1a;PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下&#xff0c;适配我自己的需求 有一个站点存在多个采集站&#xff0c;我想通过主站拿标题&#xff0c;采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...

Android写一个捕获全局异常的工具类

项目开发和实际运行过程中难免会遇到异常发生&#xff0c;系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler&#xff0c;它是Thread的子类&#xff08;就是package java.lang;里线程的Thread&#xff09;。本文将利用它将设备信息、报错信息以及错误的发生时间都…...