% e5 W' V. r! ~& W+ w
9 b' i2 x* J2 ]
& `: i7 Y% e' _. E9 ?0 P
9 x( l* ~2 B. k) l4 ~* Y8 p
9 h) o$ |6 v* {- h
# X+ @& t l5 b# j- V% t& M
1 n0 Y! t9 V9 U( R/ S4 g- a
# u) m( r5 f/ r: {& N: ^' D
- from itertools import permutations
# x2 F# t0 H0 I2 ~\" j; t- B P% Q - import math; O3 P4 ~5 U. h, ]% @! d
0 d0 B! E7 ~9 J9 ?: a6 ~! P, I- def tsp_brute(dist):
. X* [7 `8 x! I1 E - """dist: n×n 距离矩阵,返回 (最短长度, 最优回路)"""
$ q! ^# s) P* @5 F' C - n = len(dist)
9 @2 Z6 f% _5 X. |# G3 Y - best_len, best_tour = math.inf, None/ Y2 O2 X$ O& _. I: S
- for perm in permutations(range(1, n)): # 固定起点 0
) L5 x4 t% k1 X/ D1 ?8 V6 V. \ - tour = [0] + list(perm)8 ?4 Z/ \& F1 e5 n4 V* v, X4 ~- G
- L = sum(dist[tour[i]][tour[i+1]] for i in range(n-1)) + dist[tour[-1]][0]( ?/ K8 j, {( a# }, ]+ y
- if L < best_len:8 \: k( X9 q5 I( @6 D# A7 C
- best_len, best_tour = L, tour
8 Q% B& O9 d\" [+ ^# c# \4 ^ - return best_len, best_tour+ @8 r+ Y; b0 Z% L, M
- 2 z. h1 t+ E* D# u- z
- # ---------- 2-opt 局部搜索(中大规模) ----------
$ J, G\" G9 c- p) [( \5 c - def tsp_2opt(dist, max_iter=1000):
* t7 |( k$ ^1 F% i+ e - n = len(dist)
- U8 t F$ o! r8 @0 J2 l - tour = list(range(n)) # 初始:自然顺序
0 ^* K: X2 U0 w8 g: p$ _# Q j, F$ @ - improved = True! M& q) A4 X8 D# b) n
- while improved and max_iter > 0:( C) l) C' b; W' l4 n6 ]
- improved = False. l/ Z6 R0 B: J2 b1 Z
- for i in range(1, n-2):
. }1 d) a% c' L - for k in range(i+1, n):3 G1 Y( j\" F\" H% q$ ^
- # 翻转 tour[i:k+1]0 ]# `7 r: @. u3 Q$ ]
- new_tour = tour[:i] + tour[i:k+1][::-1] + tour[k+1:]
! @' f4 Z) `/ }1 L2 F' y - cur = sum(dist[tour[j]][tour[j+1]] for j in range(n-1)) + dist[tour[-1]][tour[0]] l3 u! y p0 B/ q0 l
- new = sum(dist[new_tour[j]][new_tour[j+1]] for j in range(n-1)) + dist[new_tour[-1]][new_tour[0]]# a: y. U+ J& ?: ?
- if new < cur:
/ ]& B\" H9 m; S- C - tour, improved = new_tour, True# e9 {; X4 B3 w1 X% m6 R
- max_iter -= 1
. o u5 v! o( D s - L = sum(dist[tour[j]][tour[j+1]] for j in range(n-1)) + dist[tour[-1]][tour[0]]
) ^. Y2 s& Q) d7 T( U+ X2 j - return L, tour8 I4 ~- P# I- Z: ^' c. a, D, n
+ y2 n8 F& j5 \6 x( K- # ---------- 测试:4 城市 ----------: V1 c: I( \0 W8 ~
- dist = [\" e* H5 _* V, v) M6 U T
- [0, 10, 15, 20],\" `' S! `+ Z3 F0 f+ \0 y
- [10, 0, 35, 25],
% L\" h3 r: I: ^- g/ E* j8 `/ C - [15, 35, 0, 30],- S* x) s7 K+ y, f. N
- [20, 25, 30, 0]8 S# n/ v- W4 F' k7 M
- ]
- c& |* U0 D& `9 o - print("暴力 DFS:", tsp_brute(dist)) # 最短长度 80,回路 0→1→3→2→00 H\" N! I4 H; o: f
- print("2-opt :", tsp_2opt(dist))
复制代码 7.2 运行结果- 暴力 DFS: (80, [0, 1, 3, 2])9 s, P' B1 z5 ^% S6 Z6 g
- 2-opt : (95, [0, 1, 2, 3])
复制代码观察:暴力 DFS 保证全局最优( 时可行)。2-opt 从自然顺序出发卡在局部最优 95,未能到达最优解 80——这正是 2-opt 的经典陷阱:单次运行可能陷入局部最优。竞赛中应多次随机重启或结合其他启发式(如先用最近邻初始化再 2-opt)。这也是为什么论文里必须报告"与精确解的 gap",而不是只报一个数字。 8. 竞赛真题映射年份 CUMCM 题目方向 TSP 变体 - n+ T' [& c" Y
1998B灾情巡视路线巡检 TSP(带时间窗 / 部分覆盖)$ M! V a, |: A+ h& c) \ Q
2001C公交车线路设计路径规划 + 容量约束(VRP 变体)- G: ?! o# U% f3 U
2008B啤酒运输问题配送路径优化; N# L1 x& ~: ~* k5 m
2011A高速公路收费站路网遍历 + 费用优化3 t* ^; P. ]3 A. O
2015A太阳能小屋设备布点 + 巡检路径. w' [9 I& I0 b% Q3 Y/ ]% O8 y( G
2017B煤炭产量预测无关(数据题)
% A* s E4 W2 R3 k6 Z2020A炉温曲线无关(拟合题)* N5 B ?' N0 g7 |/ p" c2 F
近年物流配送 / 应急巡检 / 传感器网络TSP / VRP / 覆盖路径核心规律:只要赛题出现"一条路走遍多个地点",TSP 或其变体(VRP、TSP with Time Windows、多车 TSP)就是最自然的建模原型。先用 TSP 建原型,再根据约束升级为 VRP,是数模竞赛的成熟套路。 9. 常见误区与赛场自查# 误区 正解
6 z$ ]& o3 @: e9 j- j% f1"TSP 可以用贪心算法精确求解"贪心(最近邻)不保证最优,存在反例( b& [/ p+ O- A* j, M$ E2 _
2"2-opt 一定得到全局最优"2-opt 是局部搜索,可能陷入局部最优6 K/ h+ Y$ {4 r3 c/ U2 c
3"TSP 和指派问题等价"TSP 要求单一回路,指派问题允许子回路
' B* U4 i0 u F6 @4"子回路消除约束可以一次性写完"数量 级别,实际用逐步加入(lazy constraint)7 L7 ]1 W8 M* G ?9 } o" t- G
5"DP 复杂度 "准确是 ,每状态需 转移
) f4 O5 z1 A0 P6"所有 TSP 都有常数近似比"仅度量 TSP(三角不等式)有 Christofides 近似$ Q2 Z W6 s* o& y: k+ e# x; C
7"对称 TSP 和非对称 TSP 一样"对称: 种回路;非对称: 种赛场自查清单: - 我确认了距离矩阵是否对称、是否满足三角不等式(影响算法选择)。
- 我估计了可行解数量 ,判断暴力 / B&B / 启发式的适用性。
- 若用 B&B:下界函数是否安全(不高于最优值)且紧?
- 若用 2-opt:是否报告了与精确解的偏差(小规模对比)?
- 若用 Christofides:是否验证了三角不等式成立?
- 论文中是否报告了运行时间与最优性差距(gap)?
- 是否对结果做了敏感性分析(距离矩阵微调时回路是否稳定)?
- 是否给出了子回路消除的处理方式(lazy constraint 或逐步加入)?
^8 V* r5 d' }
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,这是评委最认可的"务实"策略。记住:能证明最优的解,比看似漂亮但无保证的解更有说服力。 5 j# Y# K) ]( g1 q2 T) ]
: |+ B( P$ Z% V4 n! X3 H |