; U- y" @6 Q& H. w' n+ Y. |- j! L& _& R
4 x& @; v1 ]' h
8 I+ ]$ J1 S0 H: M
: F3 @' t; {2 U% @
) x1 w* \, m( G+ \% h7 _* K; g$ G
+ D! x" N* b% }0 K" g6 d
5 A0 X. Z' m+ Z3 R: `
6 B7 w) Z) n5 @7 g% |
- from itertools import permutations' E' e7 U& N6 i. i; q7 i! k
- import math+ G1 ^4 Y/ Y7 g9 L! ]2 x
- 9 k; o3 @9 |/ j' \, r
- def tsp_brute(dist):0 h; J+ N/ U\" Y0 n% Q/ f
- """dist: n×n 距离矩阵,返回 (最短长度, 最优回路)"""; `2 g* ], Z& q$ M' j
- n = len(dist)
' M. I0 ~5 E0 w& E$ _& q5 ? - best_len, best_tour = math.inf, None! V- z3 P3 |( \8 |* D
- for perm in permutations(range(1, n)): # 固定起点 0
5 P% |- h3 i7 Y. n4 d - tour = [0] + list(perm)
\" H\" E\" X3 r8 W3 ? - L = sum(dist[tour[i]][tour[i+1]] for i in range(n-1)) + dist[tour[-1]][0]: O2 K E0 f& Z4 T% g5 x: E
- if L < best_len:
) r* h% T- y' V8 { - best_len, best_tour = L, tour
9 e9 M! E4 T( p\" k1 B1 t3 s7 e- N - return best_len, best_tour! G0 a2 }+ o: P* V3 |' z% N# l
- 8 e$ J1 T+ l( @$ n
- # ---------- 2-opt 局部搜索(中大规模) ----------$ z' d O, T% G% V3 K
- def tsp_2opt(dist, max_iter=1000):
3 b# x5 i. K2 S - n = len(dist)
2 J\" z0 I/ _8 F; L$ q- n - tour = list(range(n)) # 初始:自然顺序\" ~9 {/ w3 ]( g/ W) |
- improved = True
1 u/ V. [# q z9 O3 i) U+ i2 ~- }0 S - while improved and max_iter > 0:( G) @( o+ g3 L& h# {
- improved = False
/ K2 K. v& F* Y8 ^) T. O - for i in range(1, n-2):1 c& R! d; z1 Y6 h: Y+ ?
- for k in range(i+1, n):
% S9 _. V' |) W) K, g; ^) p - # 翻转 tour[i:k+1]( v6 B# e3 H+ Z
- new_tour = tour[:i] + tour[i:k+1][::-1] + tour[k+1:]5 Y$ \/ f0 Y\" v1 m4 J
- cur = sum(dist[tour[j]][tour[j+1]] for j in range(n-1)) + dist[tour[-1]][tour[0]]# w. T( M2 [2 z' i
- new = sum(dist[new_tour[j]][new_tour[j+1]] for j in range(n-1)) + dist[new_tour[-1]][new_tour[0]]: r\" q% x( {! ?+ T6 ^9 G* M
- if new < cur:1 m: [\" R: A. Q& X* k8 [+ t
- tour, improved = new_tour, True; z, o& {% h5 I! L1 l2 }
- max_iter -= 1
4 o+ x1 U2 r! q\" _/ ] - L = sum(dist[tour[j]][tour[j+1]] for j in range(n-1)) + dist[tour[-1]][tour[0]]
' T% M2 V! |- n. C\" R - return L, tour/ G) d8 `& Y1 n# s5 F
- , Q' ]\" `! p# X: P5 ~. R- t! W
- # ---------- 测试:4 城市 ----------
/ p8 ^* ~1 X) u# {' F* u9 ?' g - dist = [1 E8 u5 e5 C' d& g1 C. x
- [0, 10, 15, 20],
2 m0 u5 T0 l# @, S9 e - [10, 0, 35, 25],
2 A\" Q& b+ G* j) w! X - [15, 35, 0, 30],
: ^! L4 k\" Z% X. m* {+ X' N( Z - [20, 25, 30, 0]
1 u- r% `% v: }\" B- L0 v; l M - ]
5 T- Z% k5 {& e - print("暴力 DFS:", tsp_brute(dist)) # 最短长度 80,回路 0→1→3→2→0
% x( \4 _) m: F) ]3 k, z5 z - print("2-opt :", tsp_2opt(dist))
复制代码 7.2 运行结果- 暴力 DFS: (80, [0, 1, 3, 2]) ]/ z# u5 J% N2 F) Y% e
- 2-opt : (95, [0, 1, 2, 3])
复制代码观察:暴力 DFS 保证全局最优( 时可行)。2-opt 从自然顺序出发卡在局部最优 95,未能到达最优解 80——这正是 2-opt 的经典陷阱:单次运行可能陷入局部最优。竞赛中应多次随机重启或结合其他启发式(如先用最近邻初始化再 2-opt)。这也是为什么论文里必须报告"与精确解的 gap",而不是只报一个数字。 8. 竞赛真题映射年份 CUMCM 题目方向 TSP 变体 ' V4 P% a+ a+ y5 {
1998B灾情巡视路线巡检 TSP(带时间窗 / 部分覆盖)8 G; {: p& Q; h) R( c0 N
2001C公交车线路设计路径规划 + 容量约束(VRP 变体)4 ?: x N- z+ X* R$ _- N: i" ]
2008B啤酒运输问题配送路径优化 r" O# a+ C1 `, r& t/ ^, `
2011A高速公路收费站路网遍历 + 费用优化# b. M5 C7 ^' h7 A. R: {. Q
2015A太阳能小屋设备布点 + 巡检路径& H. p: V2 b3 v. O ?0 S6 [
2017B煤炭产量预测无关(数据题)
$ f3 f0 h/ G8 Q/ L4 ]/ d& q) f2020A炉温曲线无关(拟合题)1 }% g. P9 ]- P% a) K
近年物流配送 / 应急巡检 / 传感器网络TSP / VRP / 覆盖路径核心规律:只要赛题出现"一条路走遍多个地点",TSP 或其变体(VRP、TSP with Time Windows、多车 TSP)就是最自然的建模原型。先用 TSP 建原型,再根据约束升级为 VRP,是数模竞赛的成熟套路。 9. 常见误区与赛场自查# 误区 正解
' N2 n9 L* q9 w% Q+ [" L1"TSP 可以用贪心算法精确求解"贪心(最近邻)不保证最优,存在反例* p% s. r. I4 m% e' n: I* m
2"2-opt 一定得到全局最优"2-opt 是局部搜索,可能陷入局部最优: J7 ?; U4 Y% l6 S; S) E; m
3"TSP 和指派问题等价"TSP 要求单一回路,指派问题允许子回路( H% m% c: H. f7 z/ j5 I+ r( ^
4"子回路消除约束可以一次性写完"数量 级别,实际用逐步加入(lazy constraint)
/ N- v! V, m8 j8 |* S' w4 p5"DP 复杂度 "准确是 ,每状态需 转移. A- [6 X1 [. i4 D
6"所有 TSP 都有常数近似比"仅度量 TSP(三角不等式)有 Christofides 近似
1 w' r# s1 r: C, j7"对称 TSP 和非对称 TSP 一样"对称: 种回路;非对称: 种赛场自查清单: - 我确认了距离矩阵是否对称、是否满足三角不等式(影响算法选择)。
- 我估计了可行解数量 ,判断暴力 / B&B / 启发式的适用性。
- 若用 B&B:下界函数是否安全(不高于最优值)且紧?
- 若用 2-opt:是否报告了与精确解的偏差(小规模对比)?
- 若用 Christofides:是否验证了三角不等式成立?
- 论文中是否报告了运行时间与最优性差距(gap)?
- 是否对结果做了敏感性分析(距离矩阵微调时回路是否稳定)?
- 是否给出了子回路消除的处理方式(lazy constraint 或逐步加入)?5 m. I4 v8 R; N+ ^
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,这是评委最认可的"务实"策略。记住:能证明最优的解,比看似漂亮但无保证的解更有说服力。
; W4 Q2 s; E6 M" i Z5 m) M4 h3 y4 b
. Z/ _! c7 \& b |