旅行商问题(TSP)的 C++ 动态规划解法教学攻略
一、问题描述
旅行商问题(TSP)是一个经典的组合优化问题。给定一个无向图,图中的顶点表示城市,边表示两个城市之间的路径,边的权重表示路径的距离。一个售货员需要从驻地出发,经过所有城市后回到驻地,要求总的路程最短。
二、输入输出形式
输入形式
输入的第一行包含两个整数 n
和 m
,分别表示顶点个数和边数。接下来的 m
行中,每行包含三个整数 u
、v
和 w
,表示顶点 u
和顶点 v
之间有一条边,边的权重为 w
。
输出形式
输出一个整数,表示最短路程的总长度。
三、样例输入输出
样例输入
5 10
1 2 3
1 3 1
1 4 5
1 5 8
2 3 6
2 4 7
2 5 9
3 4 4
3 5 2
4 5 3
样例输出
16
四、算法分析与设计
1. 动态规划算法
旅行商问题可以通过动态规划(DP)来解决。其核心思想是利用状态压缩来记录已经访问过的城市集合,并使用动态规划表来存储到达每个城市的最短路径。
2. 状态表示
定义 dp[S][i]
表示已经访问了集合 S
中的城市,最后到达城市 i
的最短路径。其中,S
是一个位掩码,表示已经访问过的城市集合。例如,S = (1 << n) - 1
表示所有城市都被访问过。
3. 状态转移
对于每个状态 S
,遍历所有可能的城市 i
,如果 i
在集合 S
中,则尝试将未访问的城市 j
加入集合 S
,更新新的状态 S | (1 << j)
的最短路径。
4. 初始状态和结果提取
初始状态为 dp[full][i] = dist[i][0]
,其中 full
表示所有城市都被访问过,dist[i][0]
是城市 i
回到起点 0
的距离。最终结果从 dp[1][0]
中提取,表示从起点 0
出发,访问所有城市后回到起点的最短路径。
五、代码实现
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
using namespace std;const int INF = 0x3f3f3f3f;int main() {int n, m;cin >> n >> m;// 初始化邻接矩阵vector<vector<int>> dist(n, vector<int>(n, INF));for (int i = 0; i < n; i++) {dist[i][i] = 0;}// 输入边信息并构建邻接矩阵for (int i = 0; i < m; i++) {int u, v, w;cin >> u >> v >> w;u--; // 转换为从 0 开始的索引v--;dist[u][v] = w;dist[v][u] = w;}// 动态规划表int full = (1 << n) - 1;vector<vector<int>> dp(1 << n, vector<int>(n, INF));// 初始化动态规划表,full 表示所有城市都被访问过for (int i = 0; i < n; i++) {dp[full][i] = dist[i][0];}// 填充动态规划表for (int S = full; S >= 0; S--) {if ((S & 1) == 0) continue; // 必须包含起点(城市 0)for (int i = 0; i < n; i++) {if (!((S >> i) & 1)) continue; // 城市 i 不在集合 S 中时跳过if (S == full) {continue; // full 已经初始化}for (int j = 0; j < n; j++) {if ((S >> j) & 1) continue; // 城市 j 已经在集合 S 中时跳过dp[S][i] = min(dp[S][i], dp[S | (1 << j)][j] + dist[i][j]);}}}// 输出结果cout << dp[1][0] << endl;return 0;
}
六、代码解析
1. 邻接矩阵初始化
首先,我们创建一个大小为 n x n
的邻接矩阵 dist
,初始化所有元素为 INF
(表示无穷大)。然后将对角线元素设置为 0
,因为每个城市到自身的距离为 0
。接下来,读取边信息并更新邻接矩阵。
2. 动态规划表初始化
定义动态规划表 dp
,其中 dp[S][i]
表示已经访问了集合 S
中的城市,最后到达城市 i
的最短路径。初始状态为 dp[full][i] = dist[i][0]
,其中 full
表示所有城市都被访问过,此时需要回到起点 0
。
3. 状态转移填充
从 full
开始,逐步减少集合的大小,填充动态规划表。对于每个状态 S
和城市 i
,如果 i
在集合 S
中,则尝试将未访问的城市 j
加入集合 S
,更新新的状态 S | (1 << j)
的最短路径。
4. 输出结果
最终结果从 dp[1][0]
中提取,表示从起点 0
出发,访问所有城市后回到起点的最短路径。
七、复杂度分析
1. 时间复杂度
动态规划的状态数为 O(2^n * n)
,每个状态需要遍历所有可能的城市 n
,因此总时间复杂度为 O(2^n * n^2)
。
2. 空间复杂度
动态规划表的空间复杂度为 O(2^n * n)
,用于存储每个状态和城市的最短路径。
八、总结
旅行商问题是一个典型的组合优化问题,通过动态规划算法可以有效地解决。该算法利用状态压缩和动态规划表,能够在合理的时间内找到最短路径。对于较小规模的问题,这种方法是可行的,但对于大规模问题,可能需要更高效的算法或启发式方法。
希望本攻略能够帮助你理解旅行商问题的动态规划解法,并能够在实际问题中应用。如果有任何疑问或需要进一步的解释,请随时提问!
相关文章:
旅行商问题(TSP)的 C++ 动态规划解法教学攻略
一、问题描述 旅行商问题(TSP)是一个经典的组合优化问题。给定一个无向图,图中的顶点表示城市,边表示两个城市之间的路径,边的权重表示路径的距离。一个售货员需要从驻地出发,经过所有城市后回到驻地&…...
unix/linux,sudo,其内部结构机制
我们现在深入sudo的“引擎室”,探究其内部的结构和运作机制。这就像我们从观察行星运动,到深入研究万有引力定律的数学表达和物理内涵一样,是理解事物本质的关键一步。 sudo 的内部结构与机制详解 sudo 的执行流程可以看作是一系列精心设计的步骤,确保了授权的准确性和安…...

Hadoop 3.x 伪分布式 8088端口无法访问问题处理
【Hadoop】YARN ResourceManager 启动后 8088 端口无法访问问题排查与解决(伪分布式启动Hadoop) 在配置和启动 Hadoop YARN 模块时,发现虽然 ResourceManager 正常启动,JPS 进程中也显示无误,但通过浏览器访问 http://主机IP:8088 时却无法打…...
Redis线程安全深度解析:单线程模型的并发智慧
Redis线程安全深度解析:单线程模型的并发智慧 引言:Redis的线程模型迷思 “Redis是单线程的”——这个广为流传的说法既正确又不完全正确。Redis的线程安全机制实际上是一套精心设计的并发控制体系,它既保持了单线程的简单性,又…...

零基础在实践中学习网络安全-皮卡丘靶场(第十期-Over Permission 模块)
经过这么长时间的学习,我相信大家已经有了很大的信心,有可能会有看不起的意思,因为皮卡丘是基础靶场,但是俗话说"基础不牢,地动山摇",所以还请大家静下心来进行学习 来翻译一下是什么意思&#…...
北京大学肖臻老师《区块链技术与应用》公开课:12-BTC-比特币的匿名性
文章目录 1.比特币的匿名性不是真的匿名,相当于化名,现金是真的匿名, 2.如果银行用化名的话和比特币的匿名哪个匿名性更好? 银行匿名性比比特币好,因为比特币的区块链的账本是完全公开的,所有人都可以查&am…...
[Harmony]网络状态监听
权限 在module.json5中添加必要权限: // 声明应用需要请求的权限列表 "requestPermissions": [{"name": "ohos.permission.GET_NETWORK_INFO", // 网络信息权限"reason": "$string:network_info_reason","…...

毕设 基于机器视觉的驾驶疲劳检测系统(源码+论文)
文章目录 0 前言1 项目运行效果2 课题背景3 Dlib人脸检测与特征提取3.1 简介3.2 Dlib优点 4 疲劳检测算法4.1 眼睛检测算法4.2 打哈欠检测算法4.3 点头检测算法 5 PyQt55.1 简介5.2相关界面代码 6 最后 0 前言 🔥这两年开始毕业设计和毕业答辩的要求和难度不断提升…...
Ubuntu18.6 学习QT问题记录以及虚拟机安装Ubuntu后的设置
Ubuntu安装 1、VM 安装 Ubuntu后窗口界面太小 Vmware Tools 工具安装的有问题 处理办法: 1、重新挂载E:\VMwareWorkstation\linux.iso文件,该文件在VMware安装目录下 2、Ubuntu桌面出现vmtools共享文件夹,将gz文件拷贝至本地,解…...
Vue3中computed和watch的区别
文章目录 前言🔍 一、computed vs watch✅ 示例对比1. computed 示例(适合模板绑定、衍生数据)2. watch 示例(副作用,如调用接口) 🧠 二、源码实现原理(简化理解)1. comp…...
发版前后的调试对照实践:用 WebDebugX 与多工具构建上线验证闭环
每次产品发版都是一次“高压时刻”。版本升级带来的不仅是新功能上线,更常伴随隐藏 bug、兼容性差异与环境同步问题。 为了降低上线风险,我们逐步构建了一套以 WebDebugX 为核心、辅以 Charles、Postman、ADB、Sentry 的发版调试与验证流程,…...
瀚文(HelloWord)智能键盘项目深度剖析:从0到1的全流程解读
瀚文(HelloWord)智能键盘项目深度剖析:从0到1的全流程解读 一、项目整体概述 瀚文(HelloWord)智能键盘是一款多功能、模块化的智能机械键盘,由三大部分组成:键盘输入模块、可替换的多功能交互…...
Shell编程核心符号与格式化操作详解
Shell编程作为Linux系统管理和自动化运维的核心技能,掌握其常用符号和格式化操作是提升脚本开发效率的关键。本文将深入解析Shell中重定向、管道符、EOF、输入输出格式化等核心概念,并通过丰富的实践案例帮助读者掌握这些重要技能。 一、信息传递与重定…...
针对“仅某个地区出现Bug”的原因分析与解决方案
一、核心排查方向(按优先级排序) 地区相关配置差异 检查点: 该地区是否有独立的配置文件或数据库分片?是否启用了地区特定的功能开关(Feature Flag)或AB测试?本地化内容(如语言、时…...

学习STC51单片机30(芯片为STC89C52RCRC)
每日一言 当你感到疲惫时,正是成长的关键时刻,再坚持一下。 IIC协议 是的,IIC协议就是与我们之前的串口通信协议是同一个性质,就是为了满足模块的通信,其实之前的串口通信协议叫做UART协议,我们千万不要弄…...
sql中group by使用场景
GROUP BY语句在SQL中用于将多个记录分组为较小的记录集合,以便对每个组执行聚合函数,如COUNT(), MAX(), MIN(), SUM(), AVG()等。GROUP BY的使用场景非常广泛,以下是一些典型的应用场景: 统计数量 当你想要计算某个字段的唯一值数…...
将HTML内容转换为Canvas图像,主流方法有效防止文本复制
HTML to Canvas 使用说明 项目概述 此项目实现了将HTML内容转换为Canvas图像的功能,可有效防止文本被复制。适用于需要保护内容的场景,如试题系统、付费内容等。 主要功能 防止复制: 将文本内容转换为Canvas图像,使用户无法选择和复制Mat…...

Python-进程
进程 简介 操作系统分配资源的基本单位 创建 依赖 依赖模块 multiprocessing 中的 Process 语法 Process(group[,target[,name[,args[,kwargs]]]]) target:如果传递了函数的引用,这个子进程就执行这里的代码args:元组的方式传递&#x…...

Paraformer分角色语音识别-中文-通用 FunASR demo测试与训练
文章目录 0 资料1 Paraformer分角色语音识别-中文-通用1 模型下载2 音频识别测试3 FunASR安装 (训练用)4 训练 0 资料 https://github.com/modelscope/FunASR/blob/main/README_zh.md https://github.com/modelscope/FunASR/blob/main/model_zoo/readm…...
【从0-1的CSS】第1篇:CSS简介,选择器以及常用样式
文章目录 CSS简介CSS的语法规则选择器id选择器元素选择器类选择器选择器优先级 CSS注释 CSS常用设置样式颜色颜色名称(常用)RGB(常用)RGBA(常用)HEX(常用)HSLHSLA 背景background-colorbackground-imagebackground-size 字体text-aligntext-decorationtext-indentline-height 边…...

对抗反爬机制的分布式爬虫自适应策略:基于强化学习的攻防博弈建模
在大数据时代,数据的价值不言而喻。网络爬虫作为获取数据的重要工具,被广泛应用于各个领域。然而,随着爬虫技术的普及,网站为了保护自身数据安全和服务器性能,纷纷采取了各种反爬机制。这就使得爬虫与反爬虫之间形成了…...
JDK21深度解密 Day 15:JDK21实战最佳实践总结
【JDK21深度解密 Day 15】JDK21实战最佳实践总结 文章简述 本篇文章是《JDK21深度解密:从新特性到生产实践的全栈指南》系列的第15篇,聚焦于JDK21实战最佳实践总结。作为Java历史上最重要的LTS版本之一,JDK21带来了虚拟线程、结构化并发、模式匹配、ZGC优化等革命性特性,…...

手写muduo网络库(一):项目构建和时间戳、日志库
引言 本文作为手写 muduo 网络库系列开篇,聚焦项目基础框架搭建与核心基础工具模块设计。通过解析 CMake 工程结构设计、目录规划原则,结合时间戳与日志系统的架构,为后续网络库开发奠定工程化基础。文中附完整 CMake 配置示例及模块代码。 …...
每日算法刷题Day25 6.7:leetcode二分答案3道题,用时1h40min(遇到两道动态规划和贪心时间较长)
3. 1631.最小体力消耗路径(中等,dfs不熟练) 1631. 最小体力消耗路径 - 力扣(LeetCode) 思想 1.你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights ,其中 heights[row][col] 表示格子 (row, col) 的高度。一开始你在最左…...

14-Oracle 23ai Vector Search 向量索引和混合索引-实操
一、Oracle 23ai支持的2种主要的向量索引类型: 1.1 内存中的邻居图向量索引 (In-Memory Neighbor Graph Vector Index) HNSW(Hierarchical Navigable Small World :分层可导航小世界)索引 是 Oracle AI Vector Search 中唯一支持的内存邻居图向量索引类…...
kubeadm安装k8s
1、环境准备 1.1、升级系统内核 参考另一篇文章:https://blog.csdn.net/u012533920/article/details/148457715?spm1011.2415.3001.5331 1.2、设置Hostname cat <<EOF > /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhos…...
服务器新建用户无法使用conda
服务器新建用户无法使用conda 1.将.bashrc文件复制到新用户家目录下 sudo cp .bashrc /home/newuser/.bashrc2.source命令激活该文件 source ~/.bashrc3.将.condarc文件复制到新用户家目录下 sudo cp .condarc/home/newuser/.condarc...

Web前端基础:JavaScript
1.JS核心语法 1.1 JS引入方式 第一种方式:内部脚本,将JS代码定义在HTML页面中 JavaScript代码必须位于<script></script>标签之间在HTML文档中,可以在任意地方,放置任意数量的<script></script>一般会把…...
基于对比学习的带钢表面缺陷分类研究,整合SimCLR自监督预训练与YOLOv8目标检测框架的技术解析及Python实现方案
以下基于对比学习的带钢表面缺陷分类研究,整合SimCLR自监督预训练与YOLOv8目标检测框架的技术解析及Python实现方案: 基于对比学习的带钢表面缺陷分类研究 ——SimCLR与YOLOv8算法融合应用 #mermaid-svg-VqDPIOfR5WJcGtD7 {font-family:"trebuchet ms",verdana,ar…...

基于AWS Serverless架构:零运维构建自动化SEO内容生成系统
作者:[Allen] 技术专栏 | 深度解析云原生SEO自动化 在流量为王的时代,持续产出高质量SEO内容成为技术运营的核心痛点。传统方案面临开发成本高、扩展性差、关键词响应滞后三大难题。本文将分享如何用AWS Serverless技术栈,构建一套零服务器运…...