; N) w5 T$ l; S
, o' O& Q g& {3 L0 n
! e% l M# w9 m" A5 x* S
. W( z3 m6 C% }, X8 u5 o
- w0 ~& H4 e- D6 h5 b1 i
- T$ d9 O/ T7 B- w" t& T
& m! {' c I# h0 M# J
/ q' v; ~# [ a' i$ A1 b. w- A
- from itertools import permutations
( U( `, n8 E, h7 s, p9 G0 q - import math% Q6 s+ k! R9 y( Z% u/ g8 W
$ A) f. x0 o) @% V1 L$ g8 i- def tsp_brute(dist):# t5 W: `3 s8 }
- """dist: n×n 距离矩阵,返回 (最短长度, 最优回路)"""
9 f% i( T' B$ ^0 I3 @! [8 e4 d - n = len(dist)) |% x2 T6 M8 h
- best_len, best_tour = math.inf, None, r. [& t1 u9 T4 n- M3 `+ `
- for perm in permutations(range(1, n)): # 固定起点 0
9 j0 ^% M( [; Q' Z# m - tour = [0] + list(perm)# w( ~6 A1 S B8 ]% C+ ^
- L = sum(dist[tour[i]][tour[i+1]] for i in range(n-1)) + dist[tour[-1]][0]: k5 Z5 l9 r\" T _ N% Q ^
- if L < best_len:8 ?8 f( | M! ~0 @7 M' s
- best_len, best_tour = L, tour T+ B, {* `8 `8 t; Z
- return best_len, best_tour2 Z' D2 w6 c; q\" i+ x
. E& s, ]5 F3 X0 f* `- # ---------- 2-opt 局部搜索(中大规模) ----------% D& K* t T. k; j0 Y
- def tsp_2opt(dist, max_iter=1000):
7 s5 E @5 z3 X) N4 B- _ - n = len(dist)
& E6 S$ e M! L2 [4 W - tour = list(range(n)) # 初始:自然顺序; a# M% l, r/ R. i1 X
- improved = True; E( \8 D1 A+ i4 I; S: u
- while improved and max_iter > 0:
% G. x; G F) \! a - improved = False4 m& }1 |( G0 w9 a, g* O7 P
- for i in range(1, n-2):9 c. d8 n9 o0 Z9 b, y
- for k in range(i+1, n):2 e( E8 x: Z- Z8 h$ ~
- # 翻转 tour[i:k+1]
4 T+ {4 F) f$ S! I+ w- G - new_tour = tour[:i] + tour[i:k+1][::-1] + tour[k+1:]4 I8 y5 X) I+ K L
- cur = sum(dist[tour[j]][tour[j+1]] for j in range(n-1)) + dist[tour[-1]][tour[0]]5 D. L9 ?. F) P/ ^9 f9 H, }
- new = sum(dist[new_tour[j]][new_tour[j+1]] for j in range(n-1)) + dist[new_tour[-1]][new_tour[0]]
- o1 T$ g8 K+ k( c( l0 L2 q - if new < cur:
& w9 |: f* q5 i. R$ u - tour, improved = new_tour, True
1 ^3 `! w. B4 a/ O j! U - max_iter -= 1
) y\" _$ a6 i5 h' P* @3 `% ]& M - L = sum(dist[tour[j]][tour[j+1]] for j in range(n-1)) + dist[tour[-1]][tour[0]]
^' e5 l3 X# S - return L, tour
+ }7 b* c: |5 c) h( M
; H+ s+ D* ]/ M5 A) q6 d- # ---------- 测试:4 城市 ----------' b5 I8 B, e5 W/ g) X
- dist = [
' O\" X( J% G8 F% l& e% `\" n - [0, 10, 15, 20],
6 X( m' b u9 o) c - [10, 0, 35, 25],* D, |' V o/ m- C' K R
- [15, 35, 0, 30],
\" G5 r7 a\" }& D - [20, 25, 30, 0]
( y' N( g' }9 u8 r- h! w. s - ]
5 z' `) }+ _: N. }! J4 o- h h - print("暴力 DFS:", tsp_brute(dist)) # 最短长度 80,回路 0→1→3→2→0 W t0 h v' R3 e+ q: K\" |/ r. i
- print("2-opt :", tsp_2opt(dist))
复制代码 7.2 运行结果- 暴力 DFS: (80, [0, 1, 3, 2])+ {5 P\" L K E& n V' E
- 2-opt : (95, [0, 1, 2, 3])
复制代码观察:暴力 DFS 保证全局最优( 时可行)。2-opt 从自然顺序出发卡在局部最优 95,未能到达最优解 80——这正是 2-opt 的经典陷阱:单次运行可能陷入局部最优。竞赛中应多次随机重启或结合其他启发式(如先用最近邻初始化再 2-opt)。这也是为什么论文里必须报告"与精确解的 gap",而不是只报一个数字。 8. 竞赛真题映射年份 CUMCM 题目方向 TSP 变体
9 _3 x2 z) b7 Y3 |8 Q' }1998B灾情巡视路线巡检 TSP(带时间窗 / 部分覆盖)
" {- R7 V7 a1 y! ^1 b+ b2001C公交车线路设计路径规划 + 容量约束(VRP 变体)
( o+ d4 g8 d f3 r: ^2008B啤酒运输问题配送路径优化6 `) c }6 U8 g
2011A高速公路收费站路网遍历 + 费用优化' x5 V l) Y2 Q7 d% G
2015A太阳能小屋设备布点 + 巡检路径0 m# L' }/ q$ E: Z
2017B煤炭产量预测无关(数据题)
8 w2 l# L8 k) E/ h2020A炉温曲线无关(拟合题)
7 R0 \9 \0 r, F" o* R$ g近年物流配送 / 应急巡检 / 传感器网络TSP / VRP / 覆盖路径核心规律:只要赛题出现"一条路走遍多个地点",TSP 或其变体(VRP、TSP with Time Windows、多车 TSP)就是最自然的建模原型。先用 TSP 建原型,再根据约束升级为 VRP,是数模竞赛的成熟套路。 9. 常见误区与赛场自查# 误区 正解 * X/ M( E M0 E0 e9 R' t
1"TSP 可以用贪心算法精确求解"贪心(最近邻)不保证最优,存在反例
" y. A2 E9 x3 M/ Z; i2"2-opt 一定得到全局最优"2-opt 是局部搜索,可能陷入局部最优
3 J1 m- x# X" Z- e3"TSP 和指派问题等价"TSP 要求单一回路,指派问题允许子回路
: n C9 Z2 x4 m, _& C Z( P& G4"子回路消除约束可以一次性写完"数量 级别,实际用逐步加入(lazy constraint)% q; m3 @4 d. N! d5 p
5"DP 复杂度 "准确是 ,每状态需 转移% _5 l& X T1 p% Y5 H; R
6"所有 TSP 都有常数近似比"仅度量 TSP(三角不等式)有 Christofides 近似0 a# P" `/ x; A9 b. W# _3 y
7"对称 TSP 和非对称 TSP 一样"对称: 种回路;非对称: 种赛场自查清单: - 我确认了距离矩阵是否对称、是否满足三角不等式(影响算法选择)。
- 我估计了可行解数量 ,判断暴力 / B&B / 启发式的适用性。
- 若用 B&B:下界函数是否安全(不高于最优值)且紧?
- 若用 2-opt:是否报告了与精确解的偏差(小规模对比)?
- 若用 Christofides:是否验证了三角不等式成立?
- 论文中是否报告了运行时间与最优性差距(gap)?
- 是否对结果做了敏感性分析(距离矩阵微调时回路是否稳定)?
- 是否给出了子回路消除的处理方式(lazy constraint 或逐步加入)?
Q9 U; Q; z3 Z" C! f$ _# U
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,这是评委最认可的"务实"策略。记住:能证明最优的解,比看似漂亮但无保证的解更有说服力。
* ] R& X" O2 E% |+ M( V q3 Z" y( i3 |# b% ^# K( A- Q- j
|