: x' }4 S# U% X* A/ u+ V. q
1 a! I) B6 }. d# j1 K; G
6 @* ~& b) s1 X6 g
& J: Z8 |/ t) W+ a) z, r7 Z
5 D( a8 n$ P$ B( j1 e3 E
j% \$ ~5 z3 P
2 R7 e- p# G: u2 E' A" Q; `8 ~, C
( y& D' `5 T. G% B' w
- from itertools import permutations) i; D* M, G2 e# |# \ ?: v
- import math
8 ~% p/ L n. s5 H# J
2 l7 N' B3 s0 k* j5 }- def tsp_brute(dist):' W; O. C+ b3 S0 U7 u
- """dist: n×n 距离矩阵,返回 (最短长度, 最优回路)"""' |+ t\" w W3 B* @' t$ M% m4 \
- n = len(dist)
3 }$ t {! ?5 U7 [3 W) C - best_len, best_tour = math.inf, None
9 y T, B) `) z' c; {9 Y6 K - for perm in permutations(range(1, n)): # 固定起点 0
$ h+ P. p4 N$ t# X& ^( g# B6 m - tour = [0] + list(perm)4 u8 J. u R9 y4 M/ `4 B\" n+ D
- L = sum(dist[tour[i]][tour[i+1]] for i in range(n-1)) + dist[tour[-1]][0]( o* o3 k5 g& I2 }: k- M; D
- if L < best_len:
% W. w\" \* P, j4 q0 I - best_len, best_tour = L, tour2 P8 O3 y\" a5 m( s
- return best_len, best_tour
4 D9 V1 k2 y+ d7 m5 ~4 [
% {- W) a+ `* Y; d- # ---------- 2-opt 局部搜索(中大规模) ----------
% x0 o7 L' f% a! a& G: \$ v - def tsp_2opt(dist, max_iter=1000):
' p+ K8 d% \8 v. {6 ? - n = len(dist)
, G8 ^% }2 Z$ H. G1 { - tour = list(range(n)) # 初始:自然顺序$ I) f; }9 B3 z' ^$ j3 |/ K
- improved = True
9 k1 x0 O+ U* { t( A: D# `% q - while improved and max_iter > 0:) `- w9 F! b4 U' _. K: u1 A
- improved = False ~! V/ \) v& M8 w, d6 b
- for i in range(1, n-2):
6 w n! Q0 q7 j - for k in range(i+1, n):+ Z6 A1 y/ @3 j/ F0 h
- # 翻转 tour[i:k+1]2 H2 G6 b! G2 g O- L
- new_tour = tour[:i] + tour[i:k+1][::-1] + tour[k+1:]/ x, `: m2 r8 Q: a& ^ T8 Z1 c0 e
- cur = sum(dist[tour[j]][tour[j+1]] for j in range(n-1)) + dist[tour[-1]][tour[0]]
/ N. d& l7 n+ [: X$ [9 L' ^ - new = sum(dist[new_tour[j]][new_tour[j+1]] for j in range(n-1)) + dist[new_tour[-1]][new_tour[0]]
! }1 I( _8 ~ s7 O8 ?# g - if new < cur:
* ^; ?! m; B; k- E; H1 e- @ - tour, improved = new_tour, True9 {. x6 _1 ?9 ^8 ?. W* M/ D
- max_iter -= 1\" L: J. H+ R* q/ j+ P0 b
- L = sum(dist[tour[j]][tour[j+1]] for j in range(n-1)) + dist[tour[-1]][tour[0]]1 Y9 \* V. Q\" O\" B6 i' n
- return L, tour t1 j! Z; t% `( `, Z
: Z0 s9 ~# P( W9 T) k6 a- # ---------- 测试:4 城市 ----------
0 d3 Q1 C* ]4 y \& o - dist = [* W# r9 k4 s' [' c0 g( ^
- [0, 10, 15, 20],
8 T) t2 [! |8 s% O) j, H: p - [10, 0, 35, 25],; Y6 s8 X, X7 v9 @3 N
- [15, 35, 0, 30],* L- x! H8 a# T ]- Q
- [20, 25, 30, 0]1 }+ K9 J6 M' P3 Z2 x) Y% v( ]
- ] f3 s* P9 k& `5 O7 S; l
- print("暴力 DFS:", tsp_brute(dist)) # 最短长度 80,回路 0→1→3→2→0% z4 L% U! ]8 c$ y4 o
- print("2-opt :", tsp_2opt(dist))
复制代码 7.2 运行结果- 暴力 DFS: (80, [0, 1, 3, 2])6 }5 G9 {! Q( x& m/ A
- 2-opt : (95, [0, 1, 2, 3])
复制代码观察:暴力 DFS 保证全局最优( 时可行)。2-opt 从自然顺序出发卡在局部最优 95,未能到达最优解 80——这正是 2-opt 的经典陷阱:单次运行可能陷入局部最优。竞赛中应多次随机重启或结合其他启发式(如先用最近邻初始化再 2-opt)。这也是为什么论文里必须报告"与精确解的 gap",而不是只报一个数字。 8. 竞赛真题映射年份 CUMCM 题目方向 TSP 变体
/ I3 x; D1 z* O3 h2 m' Y8 l1998B灾情巡视路线巡检 TSP(带时间窗 / 部分覆盖)( }( o% e/ S% M/ A
2001C公交车线路设计路径规划 + 容量约束(VRP 变体)
m3 A0 Y: C) c. i! Q" K! b, H2008B啤酒运输问题配送路径优化' ]5 Z( R2 n* L, e. G1 c3 z5 M
2011A高速公路收费站路网遍历 + 费用优化
( N/ |. n, \" k9 X S3 F2015A太阳能小屋设备布点 + 巡检路径
6 b! N1 [: G" `$ h. ~" M2017B煤炭产量预测无关(数据题): D8 \2 c0 A( o0 R" |! c# }
2020A炉温曲线无关(拟合题)! ^4 T7 g K* [9 B! N' G3 n
近年物流配送 / 应急巡检 / 传感器网络TSP / VRP / 覆盖路径核心规律:只要赛题出现"一条路走遍多个地点",TSP 或其变体(VRP、TSP with Time Windows、多车 TSP)就是最自然的建模原型。先用 TSP 建原型,再根据约束升级为 VRP,是数模竞赛的成熟套路。 9. 常见误区与赛场自查# 误区 正解
! K2 X9 V5 e% l* w+ o5 o1"TSP 可以用贪心算法精确求解"贪心(最近邻)不保证最优,存在反例( ~ j( f5 \0 b8 T S! X7 {( C
2"2-opt 一定得到全局最优"2-opt 是局部搜索,可能陷入局部最优 s8 A9 ]. j b. j/ a5 @4 u
3"TSP 和指派问题等价"TSP 要求单一回路,指派问题允许子回路
( Y8 r% v" {% T& j4"子回路消除约束可以一次性写完"数量 级别,实际用逐步加入(lazy constraint)
" S W0 |, y; }. o2 R5"DP 复杂度 "准确是 ,每状态需 转移
% X: K/ s/ Z! c. [9 }- q! Z h# j3 k6"所有 TSP 都有常数近似比"仅度量 TSP(三角不等式)有 Christofides 近似
: q8 C$ t9 @/ \; E$ ~* Z4 L" d: \8 U7"对称 TSP 和非对称 TSP 一样"对称: 种回路;非对称: 种赛场自查清单: - 我确认了距离矩阵是否对称、是否满足三角不等式(影响算法选择)。
- 我估计了可行解数量 ,判断暴力 / B&B / 启发式的适用性。
- 若用 B&B:下界函数是否安全(不高于最优值)且紧?
- 若用 2-opt:是否报告了与精确解的偏差(小规模对比)?
- 若用 Christofides:是否验证了三角不等式成立?
- 论文中是否报告了运行时间与最优性差距(gap)?
- 是否对结果做了敏感性分析(距离矩阵微调时回路是否稳定)?
- 是否给出了子回路消除的处理方式(lazy constraint 或逐步加入)?
. W. x z: q( ^7 f
10. 参考文献[1] Dantzig, G. B., Fulkerson, D. R., & Johnson, S. M. (1954). Solution of a Large-Scale Traveling-Salesman Problem. Operations Research, 2(4), 393–410. DOI: 10.1287/opre.2.4.393. https://doi.org/10.1287/opre.2.4.393 [2] Held, M., & Karp, R. M. (1961). A dynamic programming approach to sequencing problems. Proceedings of the 1961 16th ACM National Meeting, pp. 71.201–71.204. DOI: 10.1145/800029.808532. https://doi.org/10.1145/800029.808532 [3] Held, M., & Karp, R. M. (1962). The traveling-salesman problem and minimum spanning trees: Part II. Operations Research, 18(6), 1138–1162. DOI: 10.1287/opre.18.6.1138. [4] Lawler, E. L., Lenstra, J. K., Rinnooy Kan, A. H. G., & Shmoys, D. B. (Eds.) (1985). The Traveling Salesman Problem: A Guided Tour of Combinatorial Optimization. Wiley-Interscience Series in Discrete Mathematics, Vol. 12. Chichester: John Wiley & Sons. ISBN 978-0-471-90413-7. [5] Applegate, D. L., Bixby, R. E., Chvátal, V., & Cook, W. J. (2011). The Traveling Salesman Problem: A Computational Study. Princeton Series in Applied Mathematics. Princeton, NJ: Princeton University Press. ISBN 978-0-691-12993-8 (print), 978-1-400-84110-3 (ebook). https://press.princeton.edu/books/ebook/9781400841103/the-traveling-salesman-problem-pdf [6] Cook, W. (2012). In Pursuit of the Traveling Salesman: Mathematics at the Limits of Computation. Princeton, NJ: Princeton University Press. ISBN 978-0-691-16352-9. [7] 姜启源, 谢金星, 叶俊. 数学模型. 5版. 北京: 高等教育出版社, 2018. ISBN 978-7-04-049222-4. [8] 司守奎, 孙玺菁. 数学建模算法与应用. 3版. 北京: 国防工业出版社, 2021. ISBN 978-7-118-12278-7. [9] 胡运权, 主编. 运筹学教程. 5版. 北京: 清华大学出版社, 2018. ISBN 978-7-302-48125-6. https://www.tup.tsinghua.edu.cn/wap/tsxqy.aspx?id=07656604 给参赛学生的一句话:TSP 是数模优化题里"最简单的难题"——问题描述一句话,求解却需要一整套组合优化工具箱。小规模用 B&B/DP 保证最优,大规模用 2-opt 给出好解并报告 gap,这是评委最认可的"务实"策略。记住:能证明最优的解,比看似漂亮但无保证的解更有说服力。
9 y# R" R3 B, @* W" y! @6 h" C$ A* V& W0 g `
|