0 `$ T5 L$ F+ E$ c% U( n+ o/ N2 J- j* W
2 j' f# R) b( v; |
* ^+ u. B3 w( \9 t+ s7 I. C
/ M. F5 [- l7 y) e6 P
( U/ Q8 c0 Q, \2 F; F* ~! A
, v1 s# j9 x: }! A; R) p
4 f& o! w; a0 r/ v2 x3 b
7 y+ c) f$ D. X& V# r+ q
- from itertools import permutations
$ U1 y1 z\" f* Y# u - import math
% J$ ^6 p8 a @ l# x: d
. z @% A) Z\" M/ Z; Z, U- def tsp_brute(dist):. |; `4 Y8 y% P7 r\" F1 h! s! K
- """dist: n×n 距离矩阵,返回 (最短长度, 最优回路)"""* x0 u' Z5 ^0 I+ A7 D' ?
- n = len(dist)
. o* [\" A3 ^/ L, m - best_len, best_tour = math.inf, None
; [- `$ `1 D2 `5 F' G8 d - for perm in permutations(range(1, n)): # 固定起点 00 C# ]0 M0 L\" r& y* M3 f
- tour = [0] + list(perm)) W# n6 t( h) P' O
- L = sum(dist[tour[i]][tour[i+1]] for i in range(n-1)) + dist[tour[-1]][0]
( x1 g/ [* N+ e6 T - if L < best_len:
% x9 K* s# J% q - best_len, best_tour = L, tour
& @ ?5 {' m* D1 ^0 [ - return best_len, best_tour
9 k* D$ `: V) D- K. z$ Y - T\" |+ A; E9 \+ q
- # ---------- 2-opt 局部搜索(中大规模) ----------8 Z9 r/ ]& R; v/ D- d
- def tsp_2opt(dist, max_iter=1000):) o! f5 Q6 n; `( C1 v2 k t
- n = len(dist)# n# Q$ t3 i1 B2 z% I2 I- T! B
- tour = list(range(n)) # 初始:自然顺序
3 E5 @1 U2 T6 Q/ Y# c3 C& ~ - improved = True
: {9 Z% }. ~: w - while improved and max_iter > 0:6 c }2 `7 ?9 `9 U3 ?9 }- q/ X
- improved = False4 F\" @3 t/ y- t- L2 X/ {
- for i in range(1, n-2):7 L\" k) a% G$ q4 _- ~
- for k in range(i+1, n):8 d7 k; N | k- N
- # 翻转 tour[i:k+1]
) O4 w, ?! F& |( g: ? - new_tour = tour[:i] + tour[i:k+1][::-1] + tour[k+1:]
; V7 ?+ s\" j2 ~ l: A; S5 G* ]' M - cur = sum(dist[tour[j]][tour[j+1]] for j in range(n-1)) + dist[tour[-1]][tour[0]]. w3 |* ]5 L5 [7 z
- new = sum(dist[new_tour[j]][new_tour[j+1]] for j in range(n-1)) + dist[new_tour[-1]][new_tour[0]]
/ x: r/ p& I' O9 O$ ~ - if new < cur:% ~% T7 D$ @9 m) j
- tour, improved = new_tour, True0 D+ @& U3 c6 E- j# Y; T. c) o& A
- max_iter -= 1+ L6 V& K$ E1 G: k$ p
- L = sum(dist[tour[j]][tour[j+1]] for j in range(n-1)) + dist[tour[-1]][tour[0]]. v- g' X. z6 k3 F q
- return L, tour, E- V0 S6 J3 J, N; G# J5 g; V
/ n: Q! A% {4 H\" A T- # ---------- 测试:4 城市 ----------
; o F$ r0 |3 h* h5 ~, r3 ^) _ - dist = [
2 D& y2 n7 Y4 Q$ V: t - [0, 10, 15, 20],
% \3 G: M2 |; r d4 B+ T8 z3 W7 K/ R8 { - [10, 0, 35, 25],
2 P\" M+ I; F) O- H W4 P7 N - [15, 35, 0, 30],
2 \- D% _9 e% c4 t3 e/ G7 P: v - [20, 25, 30, 0]8 o; d1 L$ x6 \
- ]
; `3 A\" m$ ^7 Q& I( k k - print("暴力 DFS:", tsp_brute(dist)) # 最短长度 80,回路 0→1→3→2→0
9 m* I% ? n$ }# K+ P. O8 [7 E/ Y - print("2-opt :", tsp_2opt(dist))
复制代码 7.2 运行结果- 暴力 DFS: (80, [0, 1, 3, 2]). j* P2 d; ^6 O& G, r7 n
- 2-opt : (95, [0, 1, 2, 3])
复制代码观察:暴力 DFS 保证全局最优( 时可行)。2-opt 从自然顺序出发卡在局部最优 95,未能到达最优解 80——这正是 2-opt 的经典陷阱:单次运行可能陷入局部最优。竞赛中应多次随机重启或结合其他启发式(如先用最近邻初始化再 2-opt)。这也是为什么论文里必须报告"与精确解的 gap",而不是只报一个数字。 8. 竞赛真题映射年份 CUMCM 题目方向 TSP 变体
h x4 z4 U' i/ a$ @& F1998B灾情巡视路线巡检 TSP(带时间窗 / 部分覆盖)
3 I# |5 X( L8 ~) }& d2001C公交车线路设计路径规划 + 容量约束(VRP 变体)+ p5 u% h3 [5 }* N `1 z8 _
2008B啤酒运输问题配送路径优化) ]$ ^& j4 ^) x9 b2 l ~
2011A高速公路收费站路网遍历 + 费用优化; p2 r9 _8 n1 x' S
2015A太阳能小屋设备布点 + 巡检路径- D! Y( @1 U0 w' |$ ^
2017B煤炭产量预测无关(数据题)
4 I# j6 h2 D5 m2020A炉温曲线无关(拟合题); v7 k) w6 x1 ~6 ]( E$ y
近年物流配送 / 应急巡检 / 传感器网络TSP / VRP / 覆盖路径核心规律:只要赛题出现"一条路走遍多个地点",TSP 或其变体(VRP、TSP with Time Windows、多车 TSP)就是最自然的建模原型。先用 TSP 建原型,再根据约束升级为 VRP,是数模竞赛的成熟套路。 9. 常见误区与赛场自查# 误区 正解
A4 l. h' B8 V, v% X f: l" E1"TSP 可以用贪心算法精确求解"贪心(最近邻)不保证最优,存在反例
2 _0 d) }' _4 |/ r2"2-opt 一定得到全局最优"2-opt 是局部搜索,可能陷入局部最优
7 h" V; J1 R7 P! y2 W% u3"TSP 和指派问题等价"TSP 要求单一回路,指派问题允许子回路, [7 D" r' ~/ x
4"子回路消除约束可以一次性写完"数量 级别,实际用逐步加入(lazy constraint)
$ {0 u% H& ^" N. |5"DP 复杂度 "准确是 ,每状态需 转移
4 b7 c& E1 Q, h6"所有 TSP 都有常数近似比"仅度量 TSP(三角不等式)有 Christofides 近似
7 Z* y' D d8 c# j" [7"对称 TSP 和非对称 TSP 一样"对称: 种回路;非对称: 种赛场自查清单: - 我确认了距离矩阵是否对称、是否满足三角不等式(影响算法选择)。
- 我估计了可行解数量 ,判断暴力 / B&B / 启发式的适用性。
- 若用 B&B:下界函数是否安全(不高于最优值)且紧?
- 若用 2-opt:是否报告了与精确解的偏差(小规模对比)?
- 若用 Christofides:是否验证了三角不等式成立?
- 论文中是否报告了运行时间与最优性差距(gap)?
- 是否对结果做了敏感性分析(距离矩阵微调时回路是否稳定)?
- 是否给出了子回路消除的处理方式(lazy constraint 或逐步加入)?
% d+ ^! y$ W+ \4 ?- }( t8 k
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,这是评委最认可的"务实"策略。记住:能证明最优的解,比看似漂亮但无保证的解更有说服力。
V5 R i! T5 s% F B, V+ m' t1 x; H( t- c# e" n* O
|