& l" R' e2 ^ Q0 G1 M
9 ^! p/ D- t0 z i, y% L' u
\# [$ V8 V1 y4 k, B
+ N0 x& G! U9 Y* B. v, z" o6 }
4 c8 [1 p; j/ w! z3 ^8 B
; z( M4 [; C! [; n' a4 ^+ ^7 R8 h
) D2 T& O# E c8 |7 D4 ?
" G+ o( V) s/ U& ]
- from itertools import permutations0 t( s( f\" b' o# C! X- @
- import math
. P2 Y0 T8 G2 | @
, n- ]! U) Z, }- def tsp_brute(dist):4 Q6 B# P% u* B( J5 O
- """dist: n×n 距离矩阵,返回 (最短长度, 最优回路)"""# u8 s1 W# \& m) c4 m
- n = len(dist)7 n7 p: p B, w4 _( g$ O
- best_len, best_tour = math.inf, None
M: n( P- q p0 g$ @) z$ Q - for perm in permutations(range(1, n)): # 固定起点 0\" ~3 J% _. ]5 H0 _
- tour = [0] + list(perm)# T- Y/ q: b$ A {3 D! f8 m* X1 E
- L = sum(dist[tour[i]][tour[i+1]] for i in range(n-1)) + dist[tour[-1]][0]
# U( g; E6 T; [- @! | - if L < best_len:# M; N- C- s5 K\" M# W9 a* M) _& L
- best_len, best_tour = L, tour/ `* y( P! T5 b
- return best_len, best_tour
$ {% N) Z# G5 X* m- ]( N& I
0 R+ C! w5 X/ w- # ---------- 2-opt 局部搜索(中大规模) ----------$ H' {0 f. R' h5 D: H# t& _
- def tsp_2opt(dist, max_iter=1000):
0 A1 D* _/ C& W; j\" r9 k - n = len(dist)9 {4 X# s; ?1 r: O, P: P\" J
- tour = list(range(n)) # 初始:自然顺序) I; R$ k! G3 B3 g$ Z* S3 t
- improved = True
: `. A# c( z6 z1 }6 i1 f( u - while improved and max_iter > 0:( \' a/ l4 }; y3 J
- improved = False
8 H# D* u; C- ?7 Q x% ^( Y$ k& X7 Z - for i in range(1, n-2):
. r3 o6 K) \' C\" I - for k in range(i+1, n):
\" Z# J1 M0 _1 L% Z' `' u9 [ - # 翻转 tour[i:k+1]+ m' E5 c& `6 ]; J E1 I6 V9 x
- new_tour = tour[:i] + tour[i:k+1][::-1] + tour[k+1:]
3 I* y, q5 z+ G* Y - cur = sum(dist[tour[j]][tour[j+1]] for j in range(n-1)) + dist[tour[-1]][tour[0]]
) \- L+ `3 q8 O2 F, K ] f - new = sum(dist[new_tour[j]][new_tour[j+1]] for j in range(n-1)) + dist[new_tour[-1]][new_tour[0]]
4 D& X8 M3 }8 ? B5 P& H - if new < cur:8 ?, I7 }1 q6 ^1 b% E( D
- tour, improved = new_tour, True
8 ?, o b8 \' k1 F0 T - max_iter -= 11 j$ [3 j9 R; s/ ?+ m
- L = sum(dist[tour[j]][tour[j+1]] for j in range(n-1)) + dist[tour[-1]][tour[0]]- V- a3 \8 s\" j ~& P
- return L, tour\" M8 q0 l; o. d
, r9 ~$ {' h+ s; \ V7 z; d/ S- # ---------- 测试:4 城市 ----------$ ~6 Y' W- G* a: y# T! m/ `0 e
- dist = [
& n% t! i. C, p/ j9 g1 `4 [1 m. Y - [0, 10, 15, 20],9 F. T% O+ P6 ]. w# b, a
- [10, 0, 35, 25],) ^2 ]% ~% b/ C4 g1 m; D3 [
- [15, 35, 0, 30],
) w4 Z: ?5 h' [- C1 A\" | q7 N - [20, 25, 30, 0]
$ c\" o9 M7 d0 ?) X* J - ]/ \\" @5 k* Y: k3 Z' ^/ S
- print("暴力 DFS:", tsp_brute(dist)) # 最短长度 80,回路 0→1→3→2→0
( K7 R( W! B: ^\" V - print("2-opt :", tsp_2opt(dist))
复制代码 7.2 运行结果- 暴力 DFS: (80, [0, 1, 3, 2])
$ V5 }$ K! _) M; ]* ^ - 2-opt : (95, [0, 1, 2, 3])
复制代码观察:暴力 DFS 保证全局最优( 时可行)。2-opt 从自然顺序出发卡在局部最优 95,未能到达最优解 80——这正是 2-opt 的经典陷阱:单次运行可能陷入局部最优。竞赛中应多次随机重启或结合其他启发式(如先用最近邻初始化再 2-opt)。这也是为什么论文里必须报告"与精确解的 gap",而不是只报一个数字。 8. 竞赛真题映射年份 CUMCM 题目方向 TSP 变体
: C# l7 ~) l5 P% T6 M4 O1 O) ^1998B灾情巡视路线巡检 TSP(带时间窗 / 部分覆盖)
) w- W3 ?9 Y: F, I$ Q" `6 v2001C公交车线路设计路径规划 + 容量约束(VRP 变体)
; M. R# }7 N9 H1 v' k7 D2008B啤酒运输问题配送路径优化
$ {- i: \# k) |% f: K |2011A高速公路收费站路网遍历 + 费用优化; L" g! H X5 |( c
2015A太阳能小屋设备布点 + 巡检路径
! V6 S5 Y' C! U2 [& r! \8 b2017B煤炭产量预测无关(数据题)
1 d" I0 u+ a/ q. i: |' @2020A炉温曲线无关(拟合题)
" M# V' `( w1 r: k. V近年物流配送 / 应急巡检 / 传感器网络TSP / VRP / 覆盖路径核心规律:只要赛题出现"一条路走遍多个地点",TSP 或其变体(VRP、TSP with Time Windows、多车 TSP)就是最自然的建模原型。先用 TSP 建原型,再根据约束升级为 VRP,是数模竞赛的成熟套路。 9. 常见误区与赛场自查# 误区 正解 ; p* a- ~( |# s9 w) ^
1"TSP 可以用贪心算法精确求解"贪心(最近邻)不保证最优,存在反例' x/ k2 K% {2 f3 G1 u) p+ I
2"2-opt 一定得到全局最优"2-opt 是局部搜索,可能陷入局部最优( D! Z3 k' b: K# f
3"TSP 和指派问题等价"TSP 要求单一回路,指派问题允许子回路
4 U) Y0 W1 ?- w3 H4 t9 S0 C4"子回路消除约束可以一次性写完"数量 级别,实际用逐步加入(lazy constraint)
2 g/ b' o/ S: J- s5"DP 复杂度 "准确是 ,每状态需 转移
' ]- ^$ W$ a% A6 I6"所有 TSP 都有常数近似比"仅度量 TSP(三角不等式)有 Christofides 近似
6 z& h' u5 e: N9 } f7"对称 TSP 和非对称 TSP 一样"对称: 种回路;非对称: 种赛场自查清单: - 我确认了距离矩阵是否对称、是否满足三角不等式(影响算法选择)。
- 我估计了可行解数量 ,判断暴力 / B&B / 启发式的适用性。
- 若用 B&B:下界函数是否安全(不高于最优值)且紧?
- 若用 2-opt:是否报告了与精确解的偏差(小规模对比)?
- 若用 Christofides:是否验证了三角不等式成立?
- 论文中是否报告了运行时间与最优性差距(gap)?
- 是否对结果做了敏感性分析(距离矩阵微调时回路是否稳定)?
- 是否给出了子回路消除的处理方式(lazy constraint 或逐步加入)?
! I1 a/ P- ?; G) j2 c* M+ s( Y$ G9 w
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,这是评委最认可的"务实"策略。记住:能证明最优的解,比看似漂亮但无保证的解更有说服力。 ( a: }3 c6 X' l: w8 N4 K
$ Z& z3 c1 A; d1 L& t% b7 p |