当前位置: 首页 > 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; //获取三个盒子// 小盒…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...