Lingo编程解决TSP问题
TSP问题即巡回旅行商问题,一个商人旅行经过所有城市一次最后回到原点,问什么走法使走的路程最短。接下来用Lingo编程实现,此方法具有普遍性,建议小本本记下。
假设有6个城市
思路
利用01矩阵表示一次巡回旅行的方案。如下面矩阵代表一种方案。
(
0
1
0
0
0
0
0
0
1
0
0
0
0
0
0
1
0
0
0
0
0
0
1
0
0
0
0
0
0
1
1
0
0
0
0
0
)
\left( \begin{matrix}{} 0\quad1\quad0\quad0\quad0\quad0 \\ 0\quad0\quad1\quad0\quad0\quad0 \\ 0\quad0\quad0\quad1\quad0\quad0 \\ 0\quad0\quad0\quad0\quad1\quad0 \\ 0\quad0\quad0\quad0\quad0\quad1 \\ 1\quad0\quad0\quad0\quad0\quad0 \\ \end{matrix} \right)
⎝⎜⎜⎜⎜⎜⎜⎛010000001000000100000010000001100000⎠⎟⎟⎟⎟⎟⎟⎞
a12=1表示从城市1走到城市2。那么这个矩阵的路线为1–>2–>3–>4–>5–>6–>1。
观察这个矩阵的特点为每一行只有一个1,每一列只有一个1。但并不是这样的矩阵都是合理的,例如如下矩阵:
(
0
1
0
0
0
0
0
0
1
0
0
0
1
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
1
0
0
0
1
0
0
)
\left( \begin{matrix}{} 0\quad1\quad0\quad0\quad0\quad0 \\ 0\quad0\quad1\quad0\quad0\quad0 \\ 1\quad0\quad0\quad0\quad0\quad0 \\ 0\quad0\quad0\quad0\quad1\quad0 \\ 0\quad0\quad0\quad0\quad0\quad1 \\ 0\quad0\quad0\quad1\quad0\quad0 \\ \end{matrix} \right)
⎝⎜⎜⎜⎜⎜⎜⎛010000001000100000000010000001000100⎠⎟⎟⎟⎟⎟⎟⎞
这个矩阵的路线为:1–>2–>3–>1,4–>5–>6–>4。说明路线矩阵不能出现子圈。
总距离=路线矩阵*距离矩阵。
建立线性规划模型
设城市之间的距离用矩阵d表示,dij表示城市i与城市j的距离。
设0–1矩阵X表示经过各城市之间的路线。xij=0表示城市i不到城市j,为1则反之。
路线矩阵每一行和为1:
∑
j
=
1
n
x
i
j
=
1
,
i
=
1
,
.
.
.
,
n
(
i
≠
j
)
\sum\limits_{j = 1}^n {x_{ij} = 1,i = 1,...,n} \quad(i\ne j)
j=1∑nxij=1,i=1,...,n(i=j)
每一列和为1:
∑
i
=
1
n
x
i
j
=
1
,
j
=
1
,
.
.
.
,
n
(
j
≠
i
)
\sum\limits_{i = 1}^n {x_{ij} = 1,j = 1,...,n} \quad(j\ne i)
i=1∑nxij=1,j=1,...,n(j=i)
路线矩阵不可以出现子圈(破圈),引入额外变量u:
u
i
−
u
j
+
n
x
i
j
≤
n
−
1
,
1
<
i
≠
j
≤
n
u_i-u_j+nx_{ij}\le n-1,\quad1< i\ne j\le n
ui−uj+nxij≤n−1,1<i=j≤n
对于破圈公式的解释:
-
两个点出现子圈的情况: x i j = 1 , x j i = 1 。 x_{ij}=1,x_{ji}=1。 xij=1,xji=1。
把 x i j , x j i x_{ij},x_{ji} xij,xji代入破圈公式得: u i − u j ≤ − 1 , u j − u i ≤ − 1 u_i-u_j\le-1,\quad u_j-u_i\le-1 ui−uj≤−1,uj−ui≤−1
两式相加得: 0 ≤ − 2 0\le-2 0≤−2,显然不成立,保证了两个点不可能出现子圈。 -
对于三个点的情况: x i j = 1 , x j k = 1 , x k i = 1 x_{ij}=1,x_{jk}=1,x_{ki}=1 xij=1,xjk=1,xki=1 代入破圈公式得:
u i − u j ≤ − 1 , u j − u k ≤ − 1 , u k − u i ≤ − 1 u_i-u_j\le-1,\quad u_j-u_k\le-1,\quad u_k-u_i\le-1 ui−uj≤−1,uj−uk≤−1,uk−ui≤−1
相加得: 0 ≤ − 3 0\le-3 0≤−3,不成立,保证了三个点不出现子圈。 -
对于n个点以此类推。
此外:
x
i
j
=
0
或
1
,
i
,
j
=
1..
n
x_{ij}=0或1,i,j=1..n\quad
xij=0或1,i,j=1..n
u
i
为
实
数
,
i
=
1..
n
u_i为实数,\quad i=1..n
ui为实数,i=1..n
目标函数为:
m
i
n
z
=
∑
i
=
1
n
d
i
j
∑
j
=
1
n
x
i
j
minz= \sum\limits_{i = 1}^n {d_{ij} } \sum\limits_{j = 1}^n {x_{ij} }
minz=i=1∑ndijj=1∑nxij
Lingo编程代码如下
!TSP问题;
MODEL:
SETS:
city/1..6/:u;
link(city,city):d,x;
ENDSETS
DATA:
d=@FILE(E:\d.txt);!导入距离矩阵;
@text()=@writefor(link(i,j)|x(i,j)#GT#0:'x(',i,',',j,')=',x(i,j));!指定输出格式,输出为1的x;
ENDDATA
min=@sum(link:d*x);
@for(city(j):@sum(city(i)|j#ne#i:x(i,j))=1);!一列只有一个1;
@for(city(i):@sum(city(j)|j#ne#i:x(i,j))=1);!一行只有一个1;
@for(link(i,j)|i#ne#j#and#i#gt#1:u(i)-u(j)+6*x(i,j)<=5);!破圈;
@for(link:@bin(x));!x取0或1;
End
结果
解得最短路程是35,其路线为1–>4–>3–>2–>5–>6–>1。