' G$ |0 }6 p7 u7 I% b& n1 K
2 {5 \) Z) }9 {1 A. V) V( F
6 `+ T2 y5 b6 r, P
- O' I6 G$ m) d7 q
% K+ G, P1 r1 \" B
5 x8 x4 M% [, }4 I7 a
; m4 A7 L( C7 j* O
% B* |' f8 s" ~" v8 W0 i
- from itertools import permutations; V4 F6 R. l \
- import math
. N6 z\" h3 N! h* W
) e: S. N4 X& S3 H- def tsp_brute(dist):
/ f: u) b3 E( a$ z3 R: }0 e1 O - """dist: n×n 距离矩阵,返回 (最短长度, 最优回路)"""
5 p) M0 L. i* Z- K5 D% g7 j - n = len(dist)7 w5 l7 j( A) d2 A8 N\" `% S* }* D
- best_len, best_tour = math.inf, None
& a) T* b2 k5 a3 H\" t9 g$ u1 k9 B - for perm in permutations(range(1, n)): # 固定起点 0( U+ V/ j\" g6 B8 N7 _, k2 b4 M
- tour = [0] + list(perm)
) a) g& S& k+ d1 T+ V1 R1 y0 n - L = sum(dist[tour[i]][tour[i+1]] for i in range(n-1)) + dist[tour[-1]][0]
9 X. I! F4 \' f( g7 T3 F - if L < best_len:
: f. d! `2 e* k - best_len, best_tour = L, tour
\" Y( X9 x0 s1 O& u1 r! a - return best_len, best_tour1 F, V% w1 K1 b [
- 3 {: r5 O1 m- c' e7 Q( z
- # ---------- 2-opt 局部搜索(中大规模) ----------
; L\" f4 I$ O9 B; W. I - def tsp_2opt(dist, max_iter=1000):
- c. r; N$ t8 ?6 c6 M, F9 d* w, A - n = len(dist)
4 |- `/ ?* ~: h# M5 q2 P - tour = list(range(n)) # 初始:自然顺序9 U3 J! c8 P6 u0 L
- improved = True3 R' C+ a/ c. T3 M\" p# x8 l: L
- while improved and max_iter > 0:
- @& j7 [9 P7 f - improved = False
) M- C' J) y* j9 j2 z - for i in range(1, n-2):6 m0 V# X# E+ z- y& @% s3 h
- for k in range(i+1, n):
. H, |* j: E- {, p% L: H6 Y - # 翻转 tour[i:k+1]
7 h2 Z+ B& i$ f! B\" O* ^. z% H# K - new_tour = tour[:i] + tour[i:k+1][::-1] + tour[k+1:]- H/ R* n1 Z% v: d
- cur = sum(dist[tour[j]][tour[j+1]] for j in range(n-1)) + dist[tour[-1]][tour[0]]\" O: h9 h. Q0 v( |& e
- new = sum(dist[new_tour[j]][new_tour[j+1]] for j in range(n-1)) + dist[new_tour[-1]][new_tour[0]]+ {! E+ ^% Z2 {7 {0 s
- if new < cur:' g# D\" X$ ~, M7 F. y! e
- tour, improved = new_tour, True
$ x3 V- |+ X6 w/ T2 ] - max_iter -= 16 y) v9 Y+ U! x, ^! X0 n8 J
- L = sum(dist[tour[j]][tour[j+1]] for j in range(n-1)) + dist[tour[-1]][tour[0]]- m6 H8 O* ?0 ?2 q
- return L, tour# w' ]# B* e# c; t' r& ]% t9 ~
. e# t; n9 k4 Z1 y( u4 V- # ---------- 测试:4 城市 ----------
\" Z' e8 z( n! \* l - dist = [
( @/ [ u* d* @4 B: |5 d: K+ \ - [0, 10, 15, 20],
8 v8 U m) @/ x, ~8 d) M - [10, 0, 35, 25],
1 g' f+ _* D, ]# W7 l. {$ N - [15, 35, 0, 30],- @7 w2 ^( w& ? \! Q8 G6 w
- [20, 25, 30, 0]
, t/ R) ~5 N; H T - ]
: d8 t M$ M6 P6 R; k - print("暴力 DFS:", tsp_brute(dist)) # 最短长度 80,回路 0→1→3→2→0
4 `, R6 ~1 @- K* O% i) E1 p - print("2-opt :", tsp_2opt(dist))
复制代码 7.2 运行结果- 暴力 DFS: (80, [0, 1, 3, 2])1 f# u3 K% t* N/ O: X6 j7 x+ _! ]; J$ R
- 2-opt : (95, [0, 1, 2, 3])
复制代码观察:暴力 DFS 保证全局最优( 时可行)。2-opt 从自然顺序出发卡在局部最优 95,未能到达最优解 80——这正是 2-opt 的经典陷阱:单次运行可能陷入局部最优。竞赛中应多次随机重启或结合其他启发式(如先用最近邻初始化再 2-opt)。这也是为什么论文里必须报告"与精确解的 gap",而不是只报一个数字。 8. 竞赛真题映射年份 CUMCM 题目方向 TSP 变体 . ?% h" J* ~7 |3 `
1998B灾情巡视路线巡检 TSP(带时间窗 / 部分覆盖)/ {) E( H! y4 S2 G" i4 C+ a8 O" e$ G
2001C公交车线路设计路径规划 + 容量约束(VRP 变体)$ h( j' R4 S( M- D! |: J
2008B啤酒运输问题配送路径优化
# J/ y/ E) w, G' B8 [4 J7 [2 M2011A高速公路收费站路网遍历 + 费用优化' {# t- l5 {* q6 w2 p% l5 O
2015A太阳能小屋设备布点 + 巡检路径
- [! N% A2 H) X4 R0 E. K2017B煤炭产量预测无关(数据题)) T1 n. b ?! b* f- c# y
2020A炉温曲线无关(拟合题)% l# Z. V& P9 _& j2 d6 X G
近年物流配送 / 应急巡检 / 传感器网络TSP / VRP / 覆盖路径核心规律:只要赛题出现"一条路走遍多个地点",TSP 或其变体(VRP、TSP with Time Windows、多车 TSP)就是最自然的建模原型。先用 TSP 建原型,再根据约束升级为 VRP,是数模竞赛的成熟套路。 9. 常见误区与赛场自查# 误区 正解 * R: Q/ t( `8 f' m
1"TSP 可以用贪心算法精确求解"贪心(最近邻)不保证最优,存在反例, s& o% @. x0 u) q
2"2-opt 一定得到全局最优"2-opt 是局部搜索,可能陷入局部最优* w3 w, L5 b& e3 ?
3"TSP 和指派问题等价"TSP 要求单一回路,指派问题允许子回路
3 \2 k& Y1 l% T4 w4"子回路消除约束可以一次性写完"数量 级别,实际用逐步加入(lazy constraint)- a V# O) r3 Y9 ]: ?- q3 J
5"DP 复杂度 "准确是 ,每状态需 转移
- Y5 W6 h% A3 C G% ^# r0 i, X- z6"所有 TSP 都有常数近似比"仅度量 TSP(三角不等式)有 Christofides 近似3 Q% n R8 z& f U
7"对称 TSP 和非对称 TSP 一样"对称: 种回路;非对称: 种赛场自查清单: - 我确认了距离矩阵是否对称、是否满足三角不等式(影响算法选择)。
- 我估计了可行解数量 ,判断暴力 / B&B / 启发式的适用性。
- 若用 B&B:下界函数是否安全(不高于最优值)且紧?
- 若用 2-opt:是否报告了与精确解的偏差(小规模对比)?
- 若用 Christofides:是否验证了三角不等式成立?
- 论文中是否报告了运行时间与最优性差距(gap)?
- 是否对结果做了敏感性分析(距离矩阵微调时回路是否稳定)?
- 是否给出了子回路消除的处理方式(lazy constraint 或逐步加入)?7 |6 t# `, m" ]1 z" }; _6 _/ N. V
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,这是评委最认可的"务实"策略。记住:能证明最优的解,比看似漂亮但无保证的解更有说服力。
! [2 ]! |7 i C; K
2 E$ F, \% u, e |