【图论】求欧拉回路

news2024/9/19 10:59:02

前言

你的qq密码是否在圆周率中出现?

一个有意思的编码问题:假设密码是固定位数,设有 n n n位,每位是数字0-9,那么这样最短的“圆周率”的长度是多少?或者说求一个最短的数字串定包含所有密码。

理论

一些定义:

通过图中所有边恰好一次且行遍所有顶点的通路称为欧拉通路;
通过图中所有边恰好一次且行遍所有顶点的回路称为欧拉回路;
具有欧拉回路的无向图称为欧拉图;
具有欧拉通路但不具有欧拉回路的无向图称为半欧拉图。

求欧拉回路/通路,俗称一笔画问题,之前一直以为这个问题十分困难,直到慢慢学习揭开它的真面目。在离散课程中,学习到判断(半)欧拉图的充要条件是顶点的度数满足一定条件。具体如下
在这里插入图片描述
必要性比较容易证明,充分性是通过一个构造性证明,大致是首先找到一个回路 C C C,若回路 C C C中存在顶点 u u u有出边不在回路 C C C中,则从顶点 u u u出发dfs可以回到 u u u构成一个回路 C ′ C' C,将回路 C C C C ′ C' C合并得到一个新回路,反复操作直到所有边均访问过。

Fleury 算法

之前数学建模了解过一个Fleury算法,大意是桥不能走,个人感觉这不是≈不能走的路不能走!而且图在动态变化怎么动态地维护图中的桥,没有详细了解而且网上相关blog也比较少。
在这里插入图片描述

Hierholzer 算法

Hierholzer 算法用于在连通图中寻找欧拉路径,其流程如下:

  • 从起点出发,进行深度优先搜索。
  • 每次沿着某条边从某个顶点移动到另外一个顶点的时候,都需要删除这条边。
  • 如果没有可移动的路径,则将所在节点加入到栈中,并返回。

证明传送门:https://taodaling.github.io/blog/2019/04/25/Hierholzer%E7%AE%97%E6%B3%95/

代码模板

  • leetcode 332:你一份航线列表 tickets ,其中 tickets[i] = [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。假定所有机票至少存在一种合理的行程。且所有的机票 必须都用一次 且 只能用一次。(求有向图的欧拉通路)
  • 算法核心:访问前删除边(通常我们通过vis[]数组标记顶点已访问而不是边),并在顶点所有出边访问完后,入栈记录答案,实际上欧拉通路是递归调用返回路径构成的通路
  • 容器map嵌套priority_queue的技巧,之前自己灵光一现想到用于将数组下标拓展至负数,这里拓展为string类型,按字典序进行从小到大进行排序,但这种写法仅适用于有向图,STL优先队列没有定义erase操作
  • 时间复杂度: O ( m l o g ⁡ m ) O(mlog⁡m) O(mlogm),其中 m m m 是边的数量。对于每一条边我们需要 O ( l o g m ) O(logm) O(logm) 地删除它,最终的答案序列长度为 m + 1 m+1 m+1,而与 n n n 无关。
  • 空间复杂度: O ( m ) O(m) O(m),其中 m m m 是边的数量。我们需要存储每一条边。
unordered_map<string, 
priority_queue<string, vector<string>, std::greater<string>>> vec;

vector<string> stk;

void dfs(const string& curr) {
    while (vec.count(curr) && vec[curr].size() > 0) {
        string tmp = vec[curr].top();
        vec[curr].pop();
        dfs(tmp);
    }
    stk.emplace_back(curr);
}

vector<string> findItinerary(vector<vector<string>>& tickets) {
    for (auto& it : tickets) {
        vec[it[0]].emplace(it[1]);
    }
    dfs("JFK");
    reverse(stk.begin(), stk.end());
    return stk;
}
  • luogu P2731:求无向图的欧拉通路
  • 算法核心:访问前删除边(通常我们通过vis[]数组标记顶点已访问而不是边),并在顶点所有出边访问完后,入栈记录答案,实际上欧拉通路是递归调用返回路径构成的通路
  • 通过map<pair<int, int>, int> cnt标记边的访问,这里时间复杂度为 O ( m l o g m ) O(mlogm) O(mlogm),对cnt的自减操作实际在修改rb_tree的值,复杂度为 O ( l o g m ) O(logm) O(logm),和优先队列相同
vector<int> ans;
vector<int> g[2005];
map<pair<int, int>, int> cnt;
int m;

void dfs(int u) {
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        if (cnt[{u, v}]) {
            cnt[{u, v}]--; cnt[{v, u}]--;
            dfs(v);
        }
    }
    ans.push_back(u);
}

void Euler() {
    for (int i = 1; i <= 500; i++) {
        sort(g[i].begin(), g[i].end());
    }
    bool flag = 0;
    for (int i = 1; i <= 500; i++) {
        if (g[i].size() & 1) {
            flag = 1; dfs(i);
            break;
        }
    }
    if (!flag) {
        for (int i = 1; i <= 500; i++) {
            if (g[i].size()) {
                dfs(i);
                break;
            }
        }
    }
    reverse(ans.begin(), ans.end());
}

编码问题的解

取所有 n − 1 n-1 n1位数为节点,共 1 0 n − 1 10^{n-1} 10n1个,每个节点有10条出边和入边,设当前节点为 a 1 a 2 . . . a n − 1 a_1a_2...a_{n-1} a1a2...an1,那么它的第 r r r条出边连向节点 a 2 . . . a n − 1 r a_2...a_{n-1}r a2...an1r,这样从一个节点顺着第 r r r条边走到另一个节点,就相当于输入了数字 x x x

在节点对应的数的末尾加上某条出边的编号,就形成了一个 n n n位数,并且每个节点都能用这样的方式形成10个 n n n位数,共有 1 0 n 10^n 10n n n n位数对应所有密码,每条边映射一个密码

下图是每位只有数字0,1的情况。
在这里插入图片描述

因此问题转化不重复地遍历所有边,即为求该图的欧拉回路,由于每个节点均有10条出边和10条入边,所以答案一定存在,这符合我们的认知,一定存在包含所有密码的数字串。

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

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

相关文章

acwing1264_动态求连续区间和

目录 算法分类&#xff1a; 问题描述 算法适用题目范围&#xff1a; 实现代码&#xff1a; 算法分类&#xff1a; 树状数组/线段树 问题描述 给定 n个数组成的一个数列&#xff0c;规定有两种操作&#xff0c;一是修改某个元素&#xff0c;二是求子数列 [a,b]的连续和。 …

1602_MIT 6.828试验环境搭建

全部学习汇总&#xff1a; GreyZhang/g_unix: some basic learning about unix operating system. (github.com) 最近尝试看一下MIT的操作系统教程&#xff0c;找到了一个6.828的课程。看了一下网络上的介绍&#xff0c;看起来这个大家的认可度还是很高的。开动之前&#xff0c…

Android面经_111道安卓基础问题(四大组件BroadCast、内容提供者篇)

该文章涉及的内容主要是&#xff1a;BroadCast、内容提供者&#xff1b; Android基础问题——四大组件之BroadCast、ContentProvider 内容提供者1、BroadCast1.1、Android的广播分类1.2、Android的广播注册方式1.3、广播作用域2、内容提供者Content provider2.1、什么是内容提供…

Google Protobuf 实践使用开发

Android 敏捷开发助手 Lottie动画 轻松使用PNG、JPG等普通图片高保真转SVG图Android 完美的蒙层方案Android MMKV框架引入使用强大无匹的自定义下拉列表Google Protobuf 实践使用开发 Protobuf 实践使用前言Protobuf基本介绍Protobuf 使用配置protobuf 基本语法1. 基本使用2. …

JavaWeb-Ajax

JavaWeb-Ajax 3&#xff0c;Ajax 3.1 概述 AJAX (Asynchronous JavaScript And XML)&#xff1a;异步的 JavaScript 和 XML。 我们先来说概念中的 JavaScript 和 XML&#xff0c;JavaScript 表明该技术和前端相关&#xff1b;XML 是指以此进行数据交换。 3.1.1 作用 AJAX…

用Python绘制傅里叶级数和泰勒级数逼近已知函数的动态过程

文章目录Taylor级数Fourier级数本文代码&#xff1a; Fourier级数和Taylor级数对原函数的逼近动画Taylor级数 级数是对已知函数的一种逼近&#xff0c;比较容易理解的是Taylor级数&#xff0c;通过多项式来逼近有限区间内的函数&#xff0c;其一般形式为 f(x)∑n0Nanxnf(x)\su…

Lua 运算符 - 较为特殊部分

Lua 运算符 - 较为特殊部分 参考至菜鸟教程。 算术运算符 操作符描述实例^乘幂A^2 输出结果 100-负号-A 输出结果 -10//整除运算符(>lua5.3)5//2 输出结果 2在 lua 中&#xff0c;/ 用作除法运算&#xff0c;计算结果包含小数部分&#xff0c;// 用作整除运算&#xff0c;计…

Shiro学习文档

Shiro Java安全框架 1.什么是权限管理 ​ 基本上涉及到用户参与的系统都要进行权限管理&#xff0c;权限管理属于系统安全的范畴&#xff0c;权限管理实现对用户访问系统的控制&#xff0c;按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授权的资源。 权限管理…

oracle mysql postgresql opengauss 批量kill session

oracle alter system kill session sid,serial# immed; &#xff08;根据v$session中查出sid和serial#进行替换&#xff09; 这里提供一个常用脚本&#xff0c;支持跨实例kill会话 &#xff08;替换&1条件或放到脚本调用都行&#xff09; select alter system kill sessi…

Dubbo 简介

Apache Dubbo 是一款 RPC 服务开发框架&#xff0c;用于解决微服务架构下的服务治理与通信问题&#xff0c;官方提供了 Java、Golang 等多语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力&#xff0c; 利用 Dubbo 提供的丰富服务治理特性&…

嵌入式工程师的2022 || 2023

因为一些个人关系&#xff0c;2022年初我从北京回到了石家庄。在找工作&#xff0c;包括后续的研发工作中&#xff0c;不同地点的经历在对比中我逐渐总结出了一些经验。关于“人”方面的感悟我就不赘述了&#xff0c;下面主要在这里总结一些找工作&#xff0c;做工作的经验&…

八、迁移学习和多任务学习

文章目录1、迁移学习2、多任务学习3、端到端学习THE END1、迁移学习 \qquad迁移学习是将某个任务学习到的知识(神经网络的参数信息)迁移到另外一个相似的任务中使用&#xff0c;从而重复利用相似任务学习共同之处&#xff0c;节省模型训练的时间&#xff0c;提高模型的训练效率…

一名普通22届本科毕业生|前端程序员|22年年终总结

文章目录22年上半年&#xff1a;最后的学生时光隔离实习币基金迷茫困惑难受不要去想人生意义读书景点环境的力量再次隔离返校入职前的学习22年下半年&#xff1a;上班工作生活总结本来准备在22年年末写的&#xff0c;奈何那段时间工作太忙没抽出时间。现在是23年的1月27日&…

paddleOCR代码工程的MD模式改造

一、下载cmake_3.22.3&#xff0c;用于生成vs工程 Index of /files/v3.22 下载完成&#xff0c;解压文件&#xff0c;打开cmake-gui.exe&#xff0c;即可使用&#xff1a; 二、下载Git&#xff08;Git-2.36.0-64-bit.exe&#xff09;并按照默认路径安装&#xff0c;cmake需调用…

使用Moment格式化时间出现时间差

诶嘿&#xff0c;很离奇。前些天后端老哥给我说我这时间展示不对。 我就奇了个大怪&#xff0c;就是取的这个字段嘛&#xff0c;怎么肥事&#x1f62d; 看半天发现是时间格式化出的问题。 原代码⬇️&#xff0c;看起来没毛病嘛&#xff0c;值打印出来也与接口里的这个时间一…

到底卡在了哪里,2023年再撒谎网慢就说不过去了

前言互联网下行带来灵魂追问。钱花哪去了&#xff1f;产出在哪里&#xff1f;动辄自建的遮羞布逐步显现&#xff0c;不过自建的成本可能还不是最大的负担&#xff0c;掣肘的可能是把不重要的事情当成了主业来做&#xff0c;比如&#xff1a;互联网比如数字化转型比如研发效率和…

Verilog HDL基本语法规则

⭐本专栏针对FPGA进行入门学习&#xff0c;从数电中常见的逻辑代数讲起&#xff0c;结合Verilog HDL语言学习与仿真&#xff0c;主要对组合逻辑电路与时序逻辑电路进行分析与设计&#xff0c;对状态机FSM进行剖析与建模。 &#x1f525;文章和代码已归档至【Github仓库&#xf…

10大面试必备的排序算法 Python 实现(附源码)

今天给大家分享一篇关于Python实现排序算法的文章&#xff0c;来自GitHub。 排序算法是《数据结构与算法》中最基本的算法之一。 排序算法可以分为内部排序和外部排序&#xff0c;内部排序是数据记录在内存中进行排序&#xff0c;而外部排序是因排序的数据很大&#xff0c;一…

STM32入门基础

GPIO <1>说明 引脚电平&#xff1a;0~3.3V&#xff0c;部分可达到5V(参考引脚定义&#xff0c;带FT的就可以) 同时 GPIO有两个模式 输出模式&#xff1a;进行端口高低电平的输出&#xff0c;用于驱动LED&#xff0c;蜂鸣器等 输入模式&#xff1a;读取端口高低电平…

SimBERT剖析

SimBERT SimBERT&#xff0c;它是以Google开源的BERT模型为基础&#xff0c;基于微软的UniLM思想设计了融检索与生成于一体的任务&#xff0c;来进一步微调后得到的模型&#xff0c;所以它同时具备相似问生成和相似句检索能力。 UniLM UniLM是一个融合NLU和NLG能力的Transfo…