前言
TSP问题是广为人知的组合优化问题,它易于描述,但是难以求解。基于TSP问题的特性,决定使用通过TSP问题来学习各类启发算法,比较不同启发算法在旅行商问题上的表现。
问题
TSP问题可以描述为:现有一些节点,节点和节点之间均可相连形成边,节点之间的边存在距离,需要找到一个遍历方案先后访问所有的点,使的遍历的总距离最短。
模型
旅行商问题可以建模为一个纯整数规划模型:
目标函数最小化总距离,约束1-2保证每个节点都能进出一次,约束3保证不会出现多个圈,约束4-5保证便利顺序属于0~n-1,约束6-7约束变量为整数。
数据
数据集保存在distance.txt中,为纯距离数据,数据来源TSP问题官方dataset,共26个节点。
0 83 93 129 133 139 151 169 135 114 110 98 99 95 81 152 159 181 172 185 147 157 185 220 127 181
83 0 40 53 62 64 91 116 93 84 95 98 89 68 67 127 156 175 152 165 160 180 223 268 179 197
93 40 0 42 42 49 59 81 54 44 58 64 54 31 36 86 117 135 112 125 124 147 193 241 157 161
129 53 42 0 11 11 46 72 65 70 88 100 89 66 76 102 142 156 127 139 155 180 228 278 197 190
133 62 42 11 0 9 35 61 55 62 82 95 84 62 74 93 133 146 117 128 148 173 222 272 194 182
139 64 49 11 9 0 39 65 63 71 90 103 92 71 82 100 141 153 124 135 156 181 230 280 202 190
151 91 59 46 35 39 0 26 34 52 71 88 77 63 78 66 110 119 88 98 130 156 206 257 188 160
169 116 81 72 61 65 26 0 37 59 75 92 83 76 91 54 98 103 70 78 122 148 198 250 188 148
135 93 54 65 55 63 34 37 0 22 39 56 47 40 55 37 78 91 62 74 96 122 172 223 155 128
114 84 44 70 62 71 52 59 22 0 20 36 26 20 34 43 74 91 68 82 86 111 160 210 136 121
110 95 58 88 82 90 71 75 39 20 0 18 11 27 32 42 61 80 64 77 68 92 140 190 116 103
98 98 64 100 95 103 88 92 56 36 18 0 11 34 31 56 63 85 75 87 62 83 129 178 100 99
99 89 54 89 84 92 77 83 47 26 11 11 0 23 24 53 68 89 74 87 71 93 140 189 111 107
95 68 31 66 62 71 63 76 40 20 27 34 23 0 15 62 87 106 87 100 93 116 163 212 132 130
81 67 36 76 74 82 78 91 55 34 32 31 24 15 0 73 92 112 96 109 93 113 158 205 122 130
152 127 86 102 93 100 66 54 37 43 42 56 53 62 73 0 44 54 26 39 68 94 144 196 139 95
159 156 117 142 133 141 110 98 78 74 61 63 68 87 92 44 0 22 34 38 30 53 102 154 109 51
181 175 135 156 146 153 119 103 91 91 80 85 89 106 112 54 22 0 33 29 46 64 107 157 125 51
172 152 112 127 117 124 88 70 62 68 64 75 74 87 96 26 34 33 0 13 63 87 135 186 141 81
185 165 125 139 128 135 98 78 74 82 77 87 87 100 109 39 38 29 13 0 68 90 136 186 148 79
147 160 124 155 148 156 130 122 96 86 68 62 71 93 93 68 30 46 63 68 0 26 77 128 80 37
157 180 147 180 173 181 156 148 122 111 92 83 93 116 113 94 53 64 87 90 26 0 50 102 65 27
185 223 193 228 222 230 206 198 172 160 140 129 140 163 158 144 102 107 135 136 77 50 0 51 64 58
220 268 241 278 272 280 257 250 223 210 190 178 189 212 205 196 154 157 186 186 128 102 51 0 93 107
127 179 157 197 194 202 188 188 155 136 116 100 111 132 122 139 109 125 141 148 80 65 64 93 0 90
181 197 161 190 182 190 160 148 128 121 103 99 107 130 130 95 51 51 81 79 37 27 58 107 90 0
求解
使用ortools调用SCIP求解器对上述TSP问题进行求解。
import pandas as pd
from ortools.linear_solver import pywraplp
# 数据
distance = pd.read_table('distance.txt', header=None, index_col=None)
distance = distance.values.tolist()
city_num = len(distance)
# 求解器
solver = pywraplp.Solver.CreateSolver('SCIP')
# 决策变量
x = [[solver.IntVar(0, 1, 'x[{}][{}]'.format(i, j)) for j in range(city_num)] for i in range(city_num)]
y = [solver.IntVar(0, solver.infinity(), 'y[{}]'.format(i)) for i in range(city_num)]
# 目标函数
expression_obj = 0
for i in range(city_num):
for j in range(city_num):
expression_obj += distance[i][j] * x[i][j]
solver.Minimize(expression_obj)
# 约束
solver.Add(y[0] == 0, 'c0')
for i in range(city_num):
solver.Add(sum([x[i][j] for j in range(city_num) if i != j]) == 1, 'c1[{}]'.format(i)) # 每个城市只能进一次
solver.Add(sum([x[j][i] for j in range(city_num) if i != j]) == 1, 'c2[{}]'.format(i)) # 每个城市只能出一次
solver.Add(y[i] <= city_num - 1, 'c3[{}]'.format(i))
for j in range(1, city_num):
if i == j:
continue
solver.Add(y[j] >= y[i] + 1 - (1 - x[i][j]) * city_num, 'c4[{}][{}]'.format(i, j)) # 防止多个圈
# 求解
# print(solver.ExportModelAsLpFormat(False))
print('number of variables = ', solver.NumVariables())
print('number of constraints = ', solver.NumConstraints())
status = solver.Solve()
# 结果
if status == solver.OPTIMAL:
print('total length = ', solver.Objective().Value())
print('the travel order is:')
for i in range(city_num):
for j in range(city_num):
if y[j].solution_value() == i:
print(j)
print(0)
else:
print('no optimal solution found')
结果
总旅行距离为937
number of variables = 702
number of constraints = 704
total length = 937.0
the travel order is:
0
24
23
22
25
21
20
16
17
19
18
15
10
11
12
14
13
9
8
7
6
4
5
3
2
1
0
Process finished with exit code 0