; j; W' j, A0 ^2 \
: n8 d, y5 F$ o2 k
$ j: a( q9 B2 L1 v3 A* h
2 i! H( P: n& R8 \ ?% l- X
( [ d: J- Y! @
6 D; n6 }$ R S! P$ r
) P& r" m+ z& f A, r" P
! I) i/ P2 ]2 U" h
- from itertools import permutations
2 u( t: i1 _% H3 }+ N - import math: M0 J/ ~2 B e, {0 P
- # y, @. ?: o. p
- def tsp_brute(dist):& \( ~ |% h) A$ o- U* @3 B/ f2 Q! N
- """dist: n×n 距离矩阵,返回 (最短长度, 最优回路)"""
1 w4 T$ X# z- P. \0 d$ Y7 V - n = len(dist)0 H3 Q1 K4 R9 T }4 I
- best_len, best_tour = math.inf, None! Q\" ?6 N6 i4 \, M2 d! M( _! y
- for perm in permutations(range(1, n)): # 固定起点 0
4 b, G7 o( P0 L* l o* ]\" m2 Z) { - tour = [0] + list(perm)0 h) `$ y( k8 f- c6 u8 A3 S5 q
- L = sum(dist[tour[i]][tour[i+1]] for i in range(n-1)) + dist[tour[-1]][0]5 v# w/ D2 O# L. e5 V0 @\" E
- if L < best_len:
( _5 }! \7 a ]5 y5 q {; u - best_len, best_tour = L, tour
Z* ~\" V' D h7 C5 t - return best_len, best_tour
/ q j; _, z9 D# J) K4 O
2 Z3 }' i& r! u, G# n. d) c- # ---------- 2-opt 局部搜索(中大规模) ----------
8 a) [3 B# A2 I8 r7 t - def tsp_2opt(dist, max_iter=1000):
3 A2 d3 S6 S' t' X# v7 }8 {4 `( E# h - n = len(dist)) G$ i/ r1 E$ a! X i: R' g4 K
- tour = list(range(n)) # 初始:自然顺序! J. U: `; \4 w! A. l
- improved = True
, j# @- V\" q2 _% R8 ? - while improved and max_iter > 0:* i! j$ f! t I8 @2 o
- improved = False
\" c\" E& U$ {& l7 h: o) a - for i in range(1, n-2):# S* ]. _. P3 M) c
- for k in range(i+1, n):. D3 I( G6 b! x. i9 g
- # 翻转 tour[i:k+1]
- y4 {7 ^: Z6 } g4 A/ N5 A - new_tour = tour[:i] + tour[i:k+1][::-1] + tour[k+1:]7 \* d1 G) k, i\" P' ?+ }
- cur = sum(dist[tour[j]][tour[j+1]] for j in range(n-1)) + dist[tour[-1]][tour[0]]
# F, g5 [: I, C+ U0 s - new = sum(dist[new_tour[j]][new_tour[j+1]] for j in range(n-1)) + dist[new_tour[-1]][new_tour[0]]1 W& J# P7 X( ]- q3 c3 _: V
- if new < cur:, @\" J1 K+ g; S0 J* ` c! a8 x
- tour, improved = new_tour, True+ D; w1 a7 m: w
- max_iter -= 1' }2 E2 Z& p+ r' t0 h1 J
- L = sum(dist[tour[j]][tour[j+1]] for j in range(n-1)) + dist[tour[-1]][tour[0]]
2 G' O9 E' ~/ G) m9 E! t4 u2 a$ x- @ - return L, tour
- x* v' S8 Z! @\" S* O/ ^) w4 f
: l/ ?. i+ A9 a0 t- # ---------- 测试:4 城市 ----------
% H* _& x5 J7 ^9 D% B, Y( j - dist = [1 d: [; a9 U E' p* L
- [0, 10, 15, 20],! ]/ U$ I/ O, U$ R
- [10, 0, 35, 25],
1 b: C% x0 R\" n, F, Z% K# O' } - [15, 35, 0, 30], O8 Z\" X8 V; |( [; A! v, Q
- [20, 25, 30, 0]
: U\" m2 K! y) E - ]. X! G n$ E1 z1 t
- print("暴力 DFS:", tsp_brute(dist)) # 最短长度 80,回路 0→1→3→2→0
: P6 S7 ?/ }; v) {8 @ - print("2-opt :", tsp_2opt(dist))
复制代码 7.2 运行结果- 暴力 DFS: (80, [0, 1, 3, 2])
% {9 H0 u' Q2 k' o4 u# |- b - 2-opt : (95, [0, 1, 2, 3])
复制代码观察:暴力 DFS 保证全局最优( 时可行)。2-opt 从自然顺序出发卡在局部最优 95,未能到达最优解 80——这正是 2-opt 的经典陷阱:单次运行可能陷入局部最优。竞赛中应多次随机重启或结合其他启发式(如先用最近邻初始化再 2-opt)。这也是为什么论文里必须报告"与精确解的 gap",而不是只报一个数字。 8. 竞赛真题映射年份 CUMCM 题目方向 TSP 变体 # u2 @0 e1 X J* Y* n4 @7 X
1998B灾情巡视路线巡检 TSP(带时间窗 / 部分覆盖)- U# J' T) P* ~4 v3 P
2001C公交车线路设计路径规划 + 容量约束(VRP 变体)& f- D2 h. m+ h/ b
2008B啤酒运输问题配送路径优化3 H- `) U1 A; P5 [9 @3 N. S) @
2011A高速公路收费站路网遍历 + 费用优化6 `; `# \0 S0 |" k# u# X4 E2 w
2015A太阳能小屋设备布点 + 巡检路径" u0 ?1 V: j8 f4 ?& r: ?: _, |
2017B煤炭产量预测无关(数据题)
' [! `% n0 `/ x( h/ T$ Y2020A炉温曲线无关(拟合题)# z% G) v1 N7 S6 A. q4 q5 |/ o; j
近年物流配送 / 应急巡检 / 传感器网络TSP / VRP / 覆盖路径核心规律:只要赛题出现"一条路走遍多个地点",TSP 或其变体(VRP、TSP with Time Windows、多车 TSP)就是最自然的建模原型。先用 TSP 建原型,再根据约束升级为 VRP,是数模竞赛的成熟套路。 9. 常见误区与赛场自查# 误区 正解 4 M: N+ K5 T$ L+ n
1"TSP 可以用贪心算法精确求解"贪心(最近邻)不保证最优,存在反例
. D9 Q+ o6 E# A2"2-opt 一定得到全局最优"2-opt 是局部搜索,可能陷入局部最优6 u9 a5 `! l8 E2 b! r/ F4 k2 I
3"TSP 和指派问题等价"TSP 要求单一回路,指派问题允许子回路
6 D/ }* S: E6 s1 c: N8 _! C4"子回路消除约束可以一次性写完"数量 级别,实际用逐步加入(lazy constraint)- A+ D( }2 ] O. z6 D
5"DP 复杂度 "准确是 ,每状态需 转移
5 c; e! ~2 T7 J" H$ i6"所有 TSP 都有常数近似比"仅度量 TSP(三角不等式)有 Christofides 近似
0 f5 o: o0 h s9 H7 s, [1 X7"对称 TSP 和非对称 TSP 一样"对称: 种回路;非对称: 种赛场自查清单: - 我确认了距离矩阵是否对称、是否满足三角不等式(影响算法选择)。
- 我估计了可行解数量 ,判断暴力 / B&B / 启发式的适用性。
- 若用 B&B:下界函数是否安全(不高于最优值)且紧?
- 若用 2-opt:是否报告了与精确解的偏差(小规模对比)?
- 若用 Christofides:是否验证了三角不等式成立?
- 论文中是否报告了运行时间与最优性差距(gap)?
- 是否对结果做了敏感性分析(距离矩阵微调时回路是否稳定)?
- 是否给出了子回路消除的处理方式(lazy constraint 或逐步加入)?
% J% R9 o) V. o# @; e& F
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,这是评委最认可的"务实"策略。记住:能证明最优的解,比看似漂亮但无保证的解更有说服力。
* H0 W6 t9 E+ _, _# ^
- ] |5 W$ U9 `0 G* L3 @3 Q |