线性版本HierHolzer正确性说明

news/2024/11/28 12:33:37/文章来源:https://www.cnblogs.com/LittleDrinks/p/18571249

晚上在研究怎么求欧拉图回路,看到 \(O(n+m)\) 版本的 HierHolzer 算法实现,让我很迷惑。

void dfs(int x){for(int i = 1;i <= 500; ++i){if(g[x][i]){--g[x][i]; --g[i][x];dfs(i);}}ans[++cnt] = x;
}

OI-Wiki 上对于这段代码的描述是这样的:

将找回路的 DFS 和 Hierholzer 算法的递归合并,边找回路边使用 Hierholzer 算法。

但代码中我并没有直观地看到“边找回路边求环”的过程,而只看到了从一个点出发,有路就往下走的朴素 dfs。所以我就产生了这样的一个问题:这样的 dfs 是否能正确地找到欧拉回路呢?


首先根据欧拉图判别法我们可以知道:欧拉图中非零度顶点是连通的,且顶点的度数都是偶数。从这个性质出发,我们在脑海中随便画出一张欧拉图,以检验算法的准确性。

接下来开始证明(由于我不会做动画,所以只能尽我所能直观地描述了):

我们将这张图上度数为偶数的节点染为白色,将度数为奇数的节点染为黑色,每经过一条边就将其删去并更新颜色。显然,最开始欧拉图上都是白色的节点。

任意选取一个点开始我们的朴素 dfs。当我们走过第一条边的时候,这条边直接连接的两个顶点(起点和当前位置)都变成了黑色。当我们继续向下 dfs 的时候,每走过一条边,原先位置的黑色节点会变回白色,而当前所在的节点会变为黑色。显然,在向下 dfs 的过程中,图上要么没有黑点,要么有且仅有两个黑点。

当我们访问的某条边连接了两个黑点时,删去这条边,整张图上所有的节点又会都变为白色,此时我们就找到了(删去了)一个经过起点的环。

到这一步 dfs 并没有结束,我们也没有考虑清楚如何记录答案,但 HierHolzer 已经初具雏形了。如果称上述过程(从起点向下 dfs 又到了起点)为一次操作,我们可以发现这次操作具有如下的性质:

在一张全是白点的图上,从任意一个度数非 \(0\) 的节点(度数当然是偶数)出发,必然能找到(删去)经过这个点的一个环。(注意欧拉图上偶度节点与“必然”能找到环的联系)


继续 dfs,此时我们正第二次位于起点的位置。回顾一下我们所制定的 dfs 规则:如果有路,就一直往下走。

按照这个规则,如果此时起点的度数大于 \(0\),那么就继续往下走。换句话说,也就是重复一次上述的操作。可想而知,每一个经过起点的环都能用上述的方法找到。每经过这样的一个过程,就会删去一个经过起点的环,起点的度数就会减 \(2\),直到它变为 \(0\)

如果此时起点的度数为 \(0\),那么按照 dfs 的规则,我们就可以开始回溯了。注意此时回溯的顺序,如果我们是按照 \(1\to2\to3\to1\) 的顺序访问,那么我们应该按照 \(1\to3\to2\to1\) 的顺序回溯。每回溯到一个节点,这个节点的度数都必然是偶数,那么我们就可以重复一次操作,删去一个经过它的环。直到最后回溯到起点,我们就删去了图上所有的环。

显然,在回溯时将当前点添加到答案路径中,我们就可以将这若干个环拼成一个完整的路径。而由于这条路径的起点(所有边已经都删光,从起点回溯的时候)和终点(回溯到起点)都是我们所指定的那个起点,所以这条路径是一条回路。

综上,我们就找到了一条符合条件的欧拉回路。


这个过程还可以进行推广。
比如半欧拉图上找欧拉路的问题,就等价于过程中图上有且仅有两个黑点的情况。
比如每个环输出的顺序和遍历的顺序相反但起点不变,如果想要字典序最小欧拉回路,就要优先走编号小的节点,最后倒序输出。

至此我们再回看 HierHolzer 的流程,看似复杂而割裂的“找环——遍历环——找环”的过程就这样完美地融入在了一次 dfs 的过程中。

image

当然,如果有一天你需要脱离模板敲下完整的 HierHolzer,现场推一遍显然是不现实的。所以我们只需要坚定一个信念:

\[\color{red}{欧拉回路嘛,怎么走都是对的!} \]

附模板题 P2731 的 AC 代码

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

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

相关文章

plus_one

2024/11/26 --2024/11/28 验证哥德巴赫猜想 打印漏斗 1.统计字符 1. 不需要数组,在循环中统计各个种类的字符 2. 一定把各个种类初始化为0 3. 一个一个字符输入,不是字符串一次输入哦 4. 空格是 回车是 \n 5. 大小写字母的ASCII码不连续,所以是(s >= a&& s<…

Python基础语法 11月22日到11月26日学习过程

Python的环境配置 python安装安装地址官网网址:https://www.python.org 华为云镜像站地址:https://mirrors.huaweicloud.com/homepython根目录介绍根目录截图python的根目录【安装目录】:D:\soft\Python37Scriptspip # 从python官网上下载第三方的库 pip3.7 pip3Lib # py…

快速搭建和访问 FTP 服务器

随着以 minio 为代表的分布式系统的广泛应用,使用 FTP 的场景就越来越少了,目前仍然在一些简单的应用场景中使用。 本篇博客使用 fauria/vsftpd 的 docker 镜像,介绍 FTP 服务器搭建的两种方式:匿名访问方式 和 使用账号密码访问方式。然后使用 SpringBoot 程序通过代码访问…

Beta阶段——第十周Scrum Meeting记录

1.目前进度: (1)实现沙盒模式,基础逻辑门组件的搭建功能; (2)组件的增加,移动,旋转,删除; (3)逻辑电路的布线及删除; (4)高低电平测试;2.目前团队中存在的问题: (1)前期未能很好的使用Github仓库,导致工作进度难以同步; (2)大多数成员对Unity和C#编程语…

从软件工程的角度,谈模块为什么总是不兼容

前言 今天刚刷上Apatch,发现其没有提供Zygisk,又去酷安搜了一搜,似乎有人反应刷Lsposed不起作用,大致了解了一下,并查了些资料。下面我开始猜测以及进行理论。 说是从软件工程出发,但是实际上我并不算一个好学生,更无法代表软件工程,这或许很标题党,但是我确实想以这个…

uml用例图-2024/11/26

超市进销存管理系统

MySQL报错:sql_mode=only_full_group_by解决方法

MySQL报错:sql_mode=only_full_group_by解决方法 登录mysql之后,执行命令查看当前的sql_mode配置 select @@global.sql_mode;​​ 可以发现MySQL的sql_mode是开启了ONLY_FULL_GROUP_NY。 解决方法 把 sql_mode 中的 ONLY_FULL_GROUP_NY​去掉,其他不变即可。 找到MySQL的配置…

使用Lombok导致打印的tostring中缺少父类的属性

背景 实体类UserDto extends BaseEntity,两个类的上方都有标注,Lombok的@Data注解,但是使用时UserDto的实例对象调用toString方法时发现,只打印出来自身子类的属性信息,并没有打印出来父类的信息。@Data public class UserDto extends BaseEntity { /*** 姓名*/@TableFiel…

20222322 2024-2025-1 《网络与系统攻防技术》实验五实验报告

1.实验内容 1.1实验要求 (1)从www.besti.edu.cn、baidu.com、sina.com.cn中选择一个DNS域名进行查询,获取相关信息。 (2)尝试获取BBS、论坛、QQ、MSN中某一好友的IP地址,并查询获取该好友所在的具体地理位置。 (3)使用nmap开源软件对靶机环境进行扫描,回答以下问题并给…

华为鸿蒙智家品牌升级背后:开拓者,引领者,赋能者

今天,华为重磅推出全新品牌“华为鸿蒙智家”亮相华为Mate品牌盛典。 华为作为产业的开拓者,一直引领产业进化,带动产业从懵懂到成熟。这一次品牌升级将借势鸿蒙,为空间智能产业打开更大的想象空间。持续进化,带来更高阶的智感 作为一个热门赛道,科技巨头和家电企业均积极…

Threejs的三维坐标系

在三维空间中,所有的物体和相机都需要基于一个统一的坐标系来进行定位和操作。理解坐标系的基本概念,对于创建稳定、准确的三维效果至关重要。 基础 Three.js 采用的是右手坐标系,这意味着如果你将右手的三个手指伸直,分别指向 X、Y 和 Z 轴的方向,你的拇指指向的方向即为…

图像尺寸变换scalepadding方法

在深度学习中,当需要将图像调整到特定尺寸时,直接resize可能会导致图像失真,特别是当目标尺寸与原始图像的宽高比不一致时。为了解决这个问题,一种最常见的方法是首先按照原始图像的宽高比将图像调整到与目标尺寸最接近的尺寸,然后在剩余的空间中使用padding进行填充,以得…