【深度优先搜索】【图论】【推荐】332. 重新安排行程

news2025/2/27 14:12:06

作者推荐

动态规划的时间复杂度优化

本文涉及知识点

深度优先搜索 图论

LeetCode332. 重新安排行程

给你一份航线列表 tickets ,其中 tickets[i] = [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。
所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。
例如,行程 [“JFK”, “LGA”] 与 [“JFK”, “LGB”] 相比就更小,排序更靠前。
假定所有机票至少存在一种合理的行程。且所有的机票 必须都用一次 且 只能用一次。

示例 1:
在这里插入图片描述

输入:tickets = [[“MUC”,“LHR”],[“JFK”,“MUC”],[“SFO”,“SJC”],[“LHR”,“SFO”]]
输出:[“JFK”,“MUC”,“LHR”,“SFO”,“SJC”]
示例 2:
在这里插入图片描述

输入:tickets = [[“JFK”,“SFO”],[“JFK”,“ATL”],[“SFO”,“ATL”],[“ATL”,“JFK”],[“ATL”,“SFO”]]
输出:[“JFK”,“ATL”,“JFK”,“SFO”,“ATL”,“SFO”]
解释:另一种有效的行程是 [“JFK”,“SFO”,“ATL”,“JFK”,“ATL”,“SFO”] ,但是它字典排序更大更靠后。

提示:
1 <= tickets.length <= 300
tickets[i].length == 2
fromi.length == 3
toi.length == 3
fromi 和 toi 由大写英文字母组成
fromi != toi

基础知识

定义

如果图G中的一个路径包括每个边恰好一次,则该路径称为欧拉路径(Euler path)。
如果一个回路是欧拉路径,则称为欧拉回路(Euler circuit)。

性质

性质一:一个有向图是欧拉回路    ⟺    \iff 所有顶点的入度等于出度且该图是连通图。
性质二:一个有向图是欧拉路径    ⟺    \iff 起点出度等于入度+1,终点入度=出度+1,其它顶点的入度等于出度且该图是连通图。
欧拉路径和回路符合性质比较简单,不证明。下面只证明性质一必定是欧拉回路,性质二是欧拉路径。

证明一

设有向图G符合性质一。
操作一:以任意定点为起点s,选取s的任意临接点n1,删除sn1后,除s外,其它顶点都是出度等于入度,就是进入后,一定会离开。由于顶点的出度和入度是有限的,所以一定会结束,而结束点一定是s(因为只有它入度大于出度)。设删除经过的路径为P1。
最后一次经过s后,可能有些点入度并不为0。
→ { ∗ ∗ 操作二 ∗ ∗ 图 G 删除 P 1 各边,此时余下的边 P 2 仍然符合性质一。 P 1 经过的各点,一定有点 n 2 出度不为 0 。否则与连通图矛盾。 \rightarrow\begin{cases}**操作二**图G删除P1各边,此时余下的边P2仍然符合性质一。\\ P1经过的各点,一定有点n2出度不为0。否则与连通图矛盾。\\ \end{cases} {操作二G删除P1各边,此时余下的边P2仍然符合性质一。P1经过的各点,一定有点n2出度不为0。否则与连通图矛盾。
操作二时:如果有重边,经过几次则删除几条。
以n2为起点对P2进行操作一,得到P3,必定以n2开始和结尾。
用P3替换P1的n2节点。如此往复直到所有节点出度入度为0。

证明二

设有向图G符合性质二,s出度=入度+1,e入度=出度+1。一定存在以s为起点,e为终点的路径P1。选取方法类似证明一,多个出边任选一条出边。图G删除P1后,为P2;P2要么为空,要么符合性质二。

深度优先搜索

题目确保某条从JFK为起点的路径是欧拉路径。
如果是欧拉环路:所有点出度等于入度。
如果不是环路:起点出度-1==入度 终点入度=出度+1,其它节点入度等于出度。
必须确保起点最后访问终点那一支,其它访问顺序按字典需。

DFS 函数

在这里插入图片描述

主函数

DFS(“JFK”)
颠倒m_vRes的顺序
返回m_vRet。

示例和时序图

在这里插入图片描述
在这里插入图片描述

按时间线访问m_vRes的顺序:DAFEACBA。转置(颠倒顺序)后为:ABCAEFAD。

证明:

假定图G的欧拉路径最后一个出度大于1的节点为c,它共有m+1+n条出边,按邻接字典序排序后,第m+1条出边指向终点e。
步骤一:只讨论节点c及之后的路径。设c的临接点按字典序分别为:n[1] …n[m+n+1]。
除DFS(n[1+m] → \rightarrow e)可以直接结束,其它节点都必须等所有A的出边都访问结束(包括n[1+m]),所以 n[1+m] → \rightarrow e 的逆序最先加到vRet。
c → \rightarrow n[n+m+1]是c最后一条出边,故将 n[i+m+1] → \rightarrow c 的逆序放到vRet 中。
c → \rightarrow n[n+m ]是c最倒数第二条出边,故将 n[i+m] → \rightarrow c 的逆序放到vRet 中。
⋯ \cdots 将 n[1+m+1] → \rightarrow c 的逆序放到vRet 中。
⋮ \vdots
⋯ \cdots 将 n[m] → \rightarrow c 的逆序放到vRet 中。
⋯ \cdots n[1 ] → \rightarrow c 的逆序放到vRet 中。
将c 放到vRet 中。
步骤二:将图G 节点c及之后节点的出边都删除。c变成新的终点。
不断持续步骤一二到所有节点的出度为1。注意:c等于e也符合。

代码

核心代码

class Solution {
public:
	vector<string> findItinerary(vector<vector<string>>& tickets) {
		std::unordered_map<string, multiset<string>> mNeiBo;
		for (const auto& v : tickets)
		{
			mNeiBo[v[0]].emplace(v[1]);
		}
		DFS(mNeiBo, "JFK");
		std::reverse(m_vRet.begin(), m_vRet.end());
		return m_vRet;
	}
	void DFS(std::unordered_map<string, multiset<string>>& mNeiBo,const string& cur)
	{
		while (mNeiBo[cur].size())
		{
			auto next = *mNeiBo[cur].begin();
			mNeiBo[cur].erase(mNeiBo[cur].begin());
			DFS(mNeiBo, next);
		}
		m_vRet.emplace_back(cur);
	}
	vector<string> m_vRet;
};

测试用例

template<class T,class T2>
void Assert(const T& t1, const T2& t2)
{
	assert(t1 == t2);
}

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() != v2.size())
	{
		assert(false);
		return;
	}
	for (int i = 0; i < v1.size(); i++)
	{
		Assert(v1[i], v2[i]);
	}

}

int main()
{
	vector<vector<string>> tickets;
	{
		Solution sln;
		tickets = { {"MUC","LHR"},{"JFK","MUC"},{"SFO","SJC"},{"LHR","SFO"} };
		auto res = sln.findItinerary(tickets);
		Assert({ "JFK","MUC","LHR","SFO","SJC" }, res);
	}
	{
		Solution sln;
		tickets = { {"JFK","SFO"},{"JFK","ATL"},{"SFO","ATL"},{"ATL","JFK"},{"ATL","SFO"} };
		auto res = sln.findItinerary(tickets);
		Assert({ "JFK","ATL","JFK","SFO","ATL","SFO" }, res);
	}
}

2023年4月

class Solution {
public:
	vector<string> findItinerary(vector<vector<string>>& tickets) {		
		for (const auto& v : tickets)
		{
			m_vNeiB[v[0]].emplace(v[1]);
		}
		dfs("JFK");
		std::reverse(m_vRet.begin(), m_vRet.end());
		return m_vRet;
	}
	void dfs(const string& sCur)
	{
		while (m_vNeiB.count(sCur) && m_vNeiB[sCur].size())
		{
			const string sNext = m_vNeiB[sCur].top();
			m_vNeiB[sCur].pop();
			dfs(sNext);
		}
		m_vRet.emplace_back(sCur);
	}
	std::unordered_map < string, std::priority_queue<string, vector<string>, greater<string>>> m_vNeiB;
	vector<string> m_vRet;
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

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

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

相关文章

flutter通知栏,写得太好了

【1面 - 基础面】 你们 Android 开发的时候&#xff0c;对于 UI 稿的 px 是如何适配的&#xff1f; dpi&#xff1a;屏幕像素密度&#xff0c;指的是在系统软件上指定的单位尺寸的像素数量&#xff0c;它往往是写在系统出厂配置文件的一个固定值&#xff1b;ppi&#xff1a;也…

骨传导耳机什么牌子的好?揭秘成功法则与避坑策略

科技进步带来了骨传导耳机的兴起&#xff0c;这种耳机以其独特的优势而受到越来越多消费者的青睐。与传统的入耳式相比&#xff0c;骨传导耳机通过骨头传递声音&#xff0c;避免了对耳道的直接压迫&#xff0c;减少了对听力的潜在伤害。同时它们允许用户在享受音乐的同时&#…

Python并发编程:多线程与多进程的区别

一 谁的开启速度快 1. 在主进程下开启线程 1 2 3 4 5 6 7 8 9 from threading import Thread def work(): print("hello") if __name__ __main__: t Thread(targetwork) t.start() print("主线程/主进程") 执行结果如下&#xff1a…

十分钟三个步骤给百万级数据Excel多人同时导出添加排队导出功能,避免干崩服务器

业务场景 考虑到数据库数据日渐增多&#xff0c;导出会有全量数据的导出&#xff08;甚至有的时候数据百万级&#xff09;&#xff0c;多人同时导出可以会对服务性能造成影响&#xff0c;导出涉及到mysql查询的io操作&#xff0c;还涉及文件输入、输出流的io操作&#xff0c;所…

算法day02_209.长度最小的子数组

推荐阅读 从零开始学数组&#xff1a;深入浅出&#xff0c;带你掌握核心要点 初探二分法 再探二分法 目录 推荐阅读209.长度最小的子数组题目思路解法暴力解法队列相加法&#xff08;滑动窗口&#xff09;对列相减法&#xff08;滑动窗口&#xff09; 系统的纪录一下刷算法的过…

特斯拉一面算法原题

来自太空的 X 帖子 埃隆马斯克&#xff08;Elon Musk&#xff09;旗下太空探索技术公司 SpaceX 于 2 月 26 号&#xff0c;从太空往社交平台 X&#xff08;前身为推特&#xff0c;已被马斯克全资收购并改名&#xff09;发布帖子。 这是 SpaceX 官号首次通过星链来发送 X 帖子&a…

Rocky Linux 运维工具yum

一、yum的简介 ​​yum​是用于在基于RPM包管理系统的包管理工具。用户可以通过 ​yum​来搜索、安装、更新和删除软件包&#xff0c;自动处理依赖关系&#xff0c;方便快捷地管理系统上的软件。 二、yum的参数说明 1、install 用于在系统的上安装一个或多个软件包 2、seach 用…

React中使用useActive

1.引入 import { useActivate } from "react-activation";2.React Activation 在React中使用react-activation,其实就是类似于Vue中的keep-alive&#xff0c;实现数据的缓存&#xff1b; 源码&#xff1a; import { ReactNode, ReactNodeArray, Context, Component…

密码学在 Web3 钱包中的应用:私钥是什么?bitget钱包为例

在非对称加密演算法中&#xff0c;私钥是一串随机生成的数字&#xff0c;通常以十六进制数表示&#xff08;也就是由0、1、2、3、4、5、6、7、8、9、a、b、c、d、e和f组成&#xff09;。私钥生成后&#xff0c;这串数字被作为一个单向数学函数中的输入值&#xff0c;计算产生的…

python web框架fastapi模板渲染--Jinja2使用技巧总结

文章目录 1.jinja2模板1.1、jinja2 的变量1.1.1 列表类型数据渲染1.1.2 字典类型数据渲染 2. jinja2 的过滤器3. jinja2 的控制结构3.1、分支控制3.2、循环控制 1.jinja2模板 要了解jinja2&#xff0c;那么需要先理解模板的概念。模板在Python的web开发中⼴泛使⽤&#xff0c;…

Python多线程编程:深入理解threading模块及代码实战【第99篇—Multiprocessing模块】

Python多线程编程&#xff1a;深入理解threading模块及代码实战 在Python编程中&#xff0c;多线程是一种常用的并发编程方式&#xff0c;它可以有效地提高程序的执行效率&#xff0c;特别是在处理I/O密集型任务时。Python提供了threading模块&#xff0c;使得多线程编程变得相…

springboot 注解属性转换字典

1.注解相关功能实现 定义属性注解 import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.vehicle.manager.core.serializer.DicSerializer;import java.lang.annotation.*;/*** a…

图神经网络实战——图论

图神经网络实战——图论 0. 前言1. 图属性1.1 有向图和无向图1.2 加权图与非加权图1.3 连通图非连通图1.4 其它图类型 2. 图概念2.1 基本对象2.2 图的度量指标2.2 邻接矩阵表示法 3. 图算法3.1 广度优先搜索3.2 深度优先搜索 小结系列链接 0. 前言 图论 (Graph theory) 是数学…

【深度学习:标记数据】为医生标记数据缓解疼痛

【深度学习&#xff1a;标记数据】为医生标记数据缓解疼痛 问题实验结果结论 我开始在物理学方面进行学术研究&#xff0c;但在第一年就退学了&#xff08;抱歉&#xff0c;休学了&#xff09;我的博士学位&#xff0c;并在定量金融领域做了很长一段时间。因此&#xff0c;在我…

从0到1实现五子棋游戏!!

Hello&#xff0c;好久不见宝子们&#xff0c;今天来给大家更一个五子棋的程序~ 我们今天要讲的内容如下&#xff1a; 文章目录 1.五子棋游戏介绍1.1 游戏玩法介绍&#xff1a; 2.准备工作2.1 具体操作流程 3.游戏程序主函数4.初始化棋盘4.1.定义宏变量4.2 初始化棋盘 5.打印…

git的使用 -- 代码托管平台阿里云

准备工作&#xff1a;git下载&#xff0c;环境配置git config --global user.name/user.email &#xff08;这个是注解不用加&#xff0c;这里是两行命令&#xff0c;前面相同/前后各是一个&#xff09; 注册一个网站码云、阿里云等等创建远程仓库配置SSH公钥 生成公钥 ssh-ke…

流程图怎么画?只需这几步就可以搞定!

你在工作中有没有遇到过下面这些问题&#xff1a; 思维混乱&#xff0c;想快速厘清一个项目的逻辑&#xff1b; 想让客户轻松接受自己的设计构思/产品理念等&#xff1b; 产品流程总是百密一疏&#xff0c;经常遗漏了某种用户需求&#xff1b; 想让小伙伴们快速理解一件事&…

2019年下半年教师资格证考试《综合素质》(中学)题

2.吴老师在指导青年教师时说道&#xff1a;“我们是生物老师&#xff0c;自己就知道生物的多样性和保护这种多样性的重要&#xff0c;所以对各有所长的学生&#xff0c;我们可不能做一个把学生修剪得整整齐齐的园丁。”这种说法表明教师劳动具有&#xff08; C&#xff09;。 A…

JavaScript 基础学习笔记(五):函数、作用域、匿名函数

目录 一、函数 1.1 声明和调用 1.2 形参和实参 1.3 返回值 二、作用域 2.1 全局作用域 2.2 局部作用域 三、匿名函数 3.1 函数表达式 3.2 立即执行函数 一、函数 理解函数的封装特性&#xff0c;掌握函数的语法规则 1.1 声明和调用 函数可以把具有相同或相似逻辑的代…

女性力量崛起,三八妇女节5大品牌创意案例!

随着女性意识的觉醒&#xff0c;越来越多的女性正在看见、勇敢表达自己&#xff0c;并努力提升自己、且坚定地爱自己&#xff01; 从近些年的三八妇女节主题活动中&#xff0c;我们能看到越来越多的品牌都在策划品牌、产品活动时&#xff0c;越来越注重聚焦女性成长、性别议题…