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

图的割点、割边(Tarjan算法)

        深度优先搜索的利用。


        在一个无向连通图中,如果删掉某个顶点后,图不再连通(即任意两点之间不能互相到达),我们称这样的顶点为割点

        在一个无向连通图中,如果删掉某条边后,图不在连通,这就是割边

        我们来看一个例子:

重要城市

        我们已经掌握了敌人的城市地图,为了在战争中先发制人决定向敌人的某个城市上空投放炸弹,来切断敌人城市之间的通讯和补给,城市地图如下。

         

        肉眼可见,删除二号顶点后,图便不在连通。那么我们如何设计程序来判断呢?

        最直接的方法是遍历每一个顶点,判断该点删除后,其它顶点是否连通,用邻接表存储,时间复杂度为O(N(N+M))

        现在要讲的Tarjan算法,在朴素算法的基础上优化,可以把时间复杂度降低到O(N+M)

Tarjan算法(图的割点)

        Tarjan算法相较于朴素方法,我认为就是在深度搜索的时候已经处理了哪些是割点(因为遍历的时候肯定会遇到割点),而不需要再遍历n个顶点去删除所以它的时间复杂度去除了外面的N变成了O(N+M)

        为了突出Tarjan算法部分,我们先用邻接矩阵来写这道题,时间复杂度为O(N^2)

        所以最主要的就是深度搜索部分,我们先来想一下朴素方法的深度搜索,其实就是构成了一个生成树(每一个无向连通图都有生成树)

        本图的一个生成树如上所示,num数组来记录每个顶点的时间戳(每个结点的右上角,表示第几个被访问到),如num[3]=2,表示顶点3第二个被访问。

        正如前面所说遍历的时候肯定会遇到割点,如果生成树上的一个子结点在图中不经过它的父结点就不能访问已经遍历过的其它结点,那么它的父节点就肯定是割点了。(根节点没有父节点,时间戳最小,需要另外判断)

        下面这个难题就转变了,如果判断子节点不经过父节点访问其它节点。这里我们用一个low数组来存储一个节点在不经过父节点的情况下能访问到最远结点的时间戳。 

        对于某个顶点u,如果至少一个顶点v(即顶点的儿子),使得low[v]>=num[u](两个数组都是存的时间戳),那么u点为割点。

        对于本例,5号顶点的儿子只有6号结点,且low[6]的值为3,而5号顶点的时间戳为num[5]为5,low[6]<num[5],可以回到祖先,因此5号结点不是割点。 2号顶点的时间戳为num[2]为3,low[5]=3,low[5]==num[2],不可以回到祖先,因此2号结点不是割点。

        完整代码:(详细理解深度搜索部分)

#include<stdio.h>
int n,m;/*顶点数和边数*/
int root;/*根结点*/
int e[9][9]={0};/*邻接矩阵*/
int num[9]={0},low[9]={0},flag[9]={0};
/*num记录时间戳,low记录不经过父节点到达的最远时间戳
flag记录是否为割点*/int min(int a,int b)
{return a<b ? a:b;
}void dfs(int cur,int father,int index)
{int child=0;index++;num[cur]=index;low[cur]=index;for (int i = 1; i <= n; i++){if (e[cur][i]==1){if (num[i]==0)/*i顶点没有杯访问过*/{child++;/*子结点+1*/dfs(i,cur,index);/*继续往下遍历*/low[cur]=min(low[cur],low[i]);/*包含通过子节点访问的最早时间戳*/if (cur!=root && low[i]>= num[cur])/*当前结点不为根结点,子节点不能不通过父节点访问到之前的结点,该点为割点*//*不能为根结点是因为low[i]最小为root*/{flag[cur]=1;}else if(cur==root && child>=2)/*为根结点,且在生成树中(不是图),有两个儿子*//*生成树中有两个儿子肯定是割点,没有两个儿子也有可能是割点*/flag[cur]=1;}else if (i!=father)/*访问到的不是父节点,代表可以绕过了父节点*/{low[cur]=min(low[cur],num[i]);}     }}return ;
}int main()
{int x,y;scanf("%d %d",&n,&m);for (int i = 1; i <= m; i++){scanf("%d%d",&x,&y);e[x][y]=1;e[y][x]=1;/*无向图*/}root = 1;dfs(1,root,0);for (int i = 1; i <= n; i++){if (flag[i]==1){printf("%d ",i);}}return 0;
}

       

 输入格式:


        输入m+1行,第一行两个数n和m,n表示n个顶点,m表示m条边。接下来的m行,每行形如“a b”,用来表示一条边。

 输出格式:


        输出一行,一个数表示花费的最少银子数。

输入样例:

6 7

1 4

1 3

4 2

3 2

2 5

2 6

5 6

输出样例:

 2

图的割边

        如下图所示,左边的图没有割边,右边的图有割边:

        图的割边其实子需要修改上面代码中的一个部分将low[v]>=num[u]改为low[v]>num[u],即到达的顶点不包括其父结点和已经遍历的时间戳小于父结点的结点,这就证明该子节点与父节点相连的边为割边

        由于割边不需要额外判断是否为根节点,故判断那一部分可以删除。

        完整代码(注意输出部分):

#include<stdio.h>
int n,m;/*顶点数和边数*/
int root;/*根结点*/
int e[9][9]={0};/*邻接矩阵*/
int num[9]={0},low[9]={0};
/*num记录时间戳,low记录不经过父节点到达的最远时间戳*/int min(int a,int b)
{return a<b ? a:b;
}void dfs(int cur,int father,int index)
{index++;num[cur]=index;low[cur]=index;for (int i = 1; i <= n; i++){if (e[cur][i]==1){if (num[i]==0)/*i顶点没有杯访问过*/{dfs(i,cur,index);/*继续往下遍历*/low[cur]=min(low[cur],low[i]);/*包含通过子节点访问的最早时间戳*/if (low[i] > num[cur]){printf("%d-%d\n",cur,i);}}else if (i != father)/*访问到的不是父节点,代表可以绕过了父节点*/{low[cur]=min(low[cur],num[i]);}     }}return ;
}int main()
{int x,y;scanf("%d %d",&n,&m);for (int i = 1; i <= m; i++){scanf("%d%d",&x,&y);e[x][y]=1;e[y][x]=1;/*无向图*/}root = 1;dfs(1,root,0);    return 0;
}

输入格式:


        输入m+1行,第一行两个数n和m,n表示n个顶点,m表示m条边。接下来的m行,每行形如“a b”,用来表示一条边。

 输出格式:


        输出一行,一个数表示花费的最少银子数。

输入样例:

6 6

1 4

1 3

4 2

3 2

2 5

5 6

输出样例:

5-6

2-5

参考文献: 

《啊哈!算法》

相关文章:

图的割点、割边(Tarjan算法)

深度优先搜索的利用。 在一个无向连通图中&#xff0c;如果删掉某个顶点后&#xff0c;图不再连通&#xff08;即任意两点之间不能互相到达&#xff09;&#xff0c;我们称这样的顶点为割点。 在一个无向连通图中&#xff0c;如果删掉某条边后&#xff0c;图不在连通&#xff0…...

算法学习(十四)—— 二叉树的深度搜索(DFS)

目录 关于dfs 部分OJ题详解 2331. 计算布尔二叉树的值 129. 求根节点到叶节点数字之和 814. 二叉树剪枝 98. 验证二叉搜索树 230. 二叉搜索树中第K小的元素 257. 二叉树的所有路径 关于dfs 算法学习&#xff08;十二&#xff09;—— 递归&#xff0c;搜索&#xff0c…...

【vue2】封装自定义的日历组件(三)之基础添加月份的加减定位到最新月份的第一天

我们在切换月份的时候&#xff0c;希望高亮显示在每个月的第一天上面&#xff0c;这样的效果我们要怎么来实现&#xff0c;其实也很简单&#xff0c;我们先看下实现的效果 实现效果 代码实现 原理就是获取到每月的第一天日期&#xff0c;然后再跟整个的数据进行对比&#xff…...

LabVIEW偏心圆筒流变仪测控系统

偏心圆筒流变仪是一种专门研究聚合物熔体在复杂流场中特殊流变行为的先进设备。通过结合硬件控制与LabVIEW软件开发&#xff0c;本系统实现了对流变仪功能的精准控制与数据采集&#xff0c;进一步提高了聚合物加工过程的研究精度和效率。 项目背景 传统的流变测量设备多集中于…...

Runloop

假设你的项目中有关tableView&#xff0c;然后还有一个定时器timer在执行&#xff0c;定时器代码如下&#xff1a; var num 0override func viewDidLoad() {super.viewDidLoad()let timer Timer(timeInterval: 1,target: self,selector: #selector(self.run),userInfo: nil,r…...

SpringBoot的Bean类三种注入方式(附带LomBok注入)

SpringBoot的Bean类三种注入方式&#xff08;附带LomBok注入&#xff09; 在 Spring Boot 中&#xff0c;Bean 的注入方式主要包括构造函数注入&#xff08;Constructor Injection&#xff09;、字段注入&#xff08;Field Injection&#xff09;以及 Setter 方法注入&#xf…...

开源向量数据库介绍说明

开源向量数据库 Milvus 特点&#xff1a;分布式、高性能&#xff0c;支持亿级向量检索。 支持的数据类型&#xff1a;文本、图像、音频、视频等。 使用场景&#xff1a;推荐系统、语义搜索、图像搜索。 数据存储后端&#xff1a;支持多种后端&#xff0c;如 SQLite、MySQL、Pos…...

【前端】深度解析 JavaScript 中的 new 关键字与构造函数

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 &#x1f4af;前言&#x1f4af;构造函数的核心特性&#x1f4af;new 关键字的执行机制&#x1f4af;实例代码与详细解析代码示例代码逐步解析 &#x1f4af;new 的内部执行模拟执行过程的详细解析 &am…...

2024年华中杯数学建模C题基于光纤传感器的平面曲线重建算法建模解题全过程文档及程序

2024年华中杯数学建模 C题 基于光纤传感器的平面曲线重建算法建模 原题再现 光纤传感技术是伴随着光纤及光通信技术发展起来的一种新型传感器技术。它是以光波为传感信号、光纤为传输载体来感知外界环境中的信号&#xff0c;其基本原理是当外界环境参数发生变化时&#xff0c…...

使用 `typing_extensions.TypeAlias` 简化类型定义:初学者指南

使用 typing_extensions.TypeAlias 简化类型定义&#xff1a;初学者指南 什么是 TypeAlias&#xff1f;安装 typing_extensions示例代码&#xff1a;如何使用 TypeAlias示例 1&#xff1a;为简单类型定义别名示例 2&#xff1a;为复杂类型定义别名示例 3&#xff1a;结合 Union…...

如何快速批量把 PDF 转为 JPG 或其它常见图像格式?

在某些特定场景下&#xff0c;将 PDF 转换为 JPG 图片格式却具有不可忽视的优势。例如&#xff0c;当我们需要在不支持 PDF 查看的设备或软件中展示文档内容时&#xff0c;JPG 图片能够轻松被识别和打开&#xff1b;此外&#xff0c;对于一些网络分享或社交媒体发布的需求&…...

如何在组织中塑造和强化绩效文化?

在组织中塑造和强化绩效文化是一个系统性的工程。 一、明确绩效目标与期望 设定清晰目标 组织应根据自身战略规划&#xff0c;将长期目标分解为具体、可衡量、可实现、相关联、有时限&#xff08;SMART&#xff09;的短期和中期绩效目标。例如&#xff0c;一家连锁餐饮企业的…...

OllyDbg、CE简单介绍

基础知识&#xff1a; 想要破解软件&#xff0c;需要一些基础知识&#xff1a; 文件格式&#xff1a;Windows对应PE、Linux对应ELF、IOS对应Mash-0。文件格式是指操作系统规定的每个段&#xff08;代码段、数据段、堆、栈&#xff09;的大小、顺序等信息。 汇编语言&#xff1…...

Python函数——函数的返回值定义语法

一、引言 在Python中&#xff0c;函数的返回值是其核心功能之一&#xff0c;它使得函数能够将计算结果传递给调用者&#xff0c;进而推动程序的逻辑和功能实现。理解和掌握函数的返回值语法&#xff0c;不仅能够提高代码的模块化和可读性&#xff0c;还能使程序更加高效和灵活…...

【Pandas】pandas isna

Pandas2.2 General Top-level missing data 方法描述isna(obj)用于检测数据中的缺失值isnull(obj)用于检测数据中的缺失值notna(obj)用于检测数据中的非缺失值notnull(obj)用于检测数据中的非缺失值 pandas.isna() pandas.isna() 是 Pandas 库中的一个函数&#xff0c;用于…...

mysql 数据库表的大小

mysql 数据库表的大小 Mysql 查看数据库各个表占用空间 mysql如何查看数据库所有表大小 在MySQL中&#xff0c;要查看数据库所有表的大小&#xff0c;可以使用以下方法&#xff1a; 方法一&#xff1a;使用information_schema数据库 首先&#xff0c;通过命令行或图形界面…...

(6)JS-Clipper2之ClipperOffset

1. 描述 ClipperOffset类封装了对打开路径和关闭路径进行偏移(膨胀/收缩)的过程。 这个类取代了现在已弃用的OffsetPaths函数&#xff0c;该函数不太灵活。可以使用不同的偏移量(增量)多次调用Execute方法&#xff0c;而不必重新分配路径。现在可以在一次操作中对开放和封闭路…...

如何在Ubuntu中利用repo和git地址下载获取imx6ull的BSP

01-设置git的用户名和邮箱 git config --global user.name "suwenhao" git config --global user.email "2487872782qq.com"这里不设置的话后面在第5步的repo配置中还是会要求输入&#xff0c;而且以后进行相关操作都要输入&#xff0c;不妨现在就进行配置…...

Ruby On Rails 笔记5——常用验证下

3.Validation Options 3.1 :allow_nil 当验证值为nil时:allow_nil选项会跳过验证 class Coffee < ApplicationRecordvalidates :size, inclusion: { in: %w(small medium large),message: "%{value} is not a valid size" }, allow_nil: true end irb> Cof…...

JS听到了因果的回响

这是我学习JS的第11天了&#xff0c;&#xff0c;&#xff0c;我现在赶着周末学JS&#xff0c;然后还有二十多天就期末了呵呵呵。。。 图片切换模块 思路分析&#xff1a; 这是实现的代码&#xff0c;建议还是把不同的变量定义出来比较合适&#xff1a; //获取三个盒子// 小盒…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...

vulnyx Blogger writeup

信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面&#xff0c;gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress&#xff0c;说明目标所使用的cms是wordpress&#xff0c;访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...