TSP问题求解,简单易懂(动态规划法、分支限界法、回溯法)


TSP问题:旅行家要旅行n个城市,每个城市经历且仅经历一次然后回到出发城市,并要求所走的路程最短。

( ∞    3    6    7 5    ∞    2    3 6    4    ∞    2 3    7    5    ∞ ) \begin{pmatrix}\infty\ \ 3\ \ 6\ \ 7\\5\ \ \infty\ \ 2\ \ 3\\6\ \ 4\ \ \infty\ \ 2\\3\ \ 7\ \ 5\ \ \infty \end{pmatrix}   3  6  75    2  36  4    23  7  5  


1.动态规划法

对于图 G = ( V , E ) G=(V, E) G=(V,E),假设从顶点 i i i出发,令 V ′ = V − i V^{'}=V-i V=Vi,则 d ( i , V ′ ) d(i, V') d(i,V)表示从顶点 i i i出发经过 V ′ V' V中各个顶点一次且仅一次,最后回到出发点 i i i的最短路径长度, 显然,初始子问题是 d ( k , { } ) d(k, \{ \}) d(k,{}),即从顶点 i i i出发只经过顶点 k k k回到顶点 i i i。现在考虑原问题的一部分, d ( k , V ′ − { k } ) d(k, V'-\{k\}) d(k,V{k})表示从顶点k出发经过 V ′ − { k } V'-\{k\} V{k}中各个顶点一次且仅一次,最后回到出发点 i i i的最短路径长度,则:

i i i为子问题起点, V ′ V^{'} V里就是子问题经过的点, V ′ V^{'} V里有几个点, m i n { } min\{\} min{}里就有几种情况

还不理解,就结合解题过程

解题过程:(括号内内容从下往上看,便于理解,即自底向上思考)

  1. 首先计算初始子问题,可以直接获得:

    d ( 1 , {   } ) = c 10 = 5 ( 1 → 0 ) d(1, \{ \ \})= c_{10} =5(1→0) d(1,{ })=c10=5(10)

    d ( 2 , {   } ) = c 20 = 6 ( 2 → 0 ) d(2, \{\ \})= c_{20} =6(2→0) d(2,{ })=c20=6(20)

    d ( 3 , {   } ) = c 30 = 3 ( 3 → 0 ) d(3, \{\ \})= c_{30} =3(3→0) d(3,{ })=c30=3(30)

  2. 再求解下一个阶段的子问题,有:
    d ( 1 , { 2 } ) = c 12 + d ( 2 , {   } ) = 2 + 6 = 8 ( 1 → 2 ) d(1, \{2\})= c_{12}+d(2, \{\ \})=2+6=8(1→2) d(1,{2})=c12+d(2,{ })=2+6=8(12)

    d ( 1 , { 3 } ) = c 13 + d ( 3 , {   } ) = 3 + 3 = 6 ( 1 → 3 ) d(1, \{3\})= c_{13}+d(3, \{\ \})=3+3=6(1→3) d(1,{3})=c13+d(3,{ })=3+3=6(13)

    d ( 2 , { 1 } ) = c 21 + d ( 1 , {   } ) = 4 + 5 = 9 ( 2 → 1 ) d(2, \{1\})= c_{21}+d(1, \{\ \})=4+5=9(2→1) d(2,{1})=c21+d(1,{ })=4+5=9(21)

    d ( 2 , { 3 } ) = c 23 + d ( 3 , {   } ) = 2 + 3 = 5 ( 2 → 3 ) d(2, \{3\})= c_{23}+d(3, \{\ \})=2+3=5(2→3) d(2,{3})=c23+d(3,{ })=2+3=5(23)

    d ( 3 , { 1 } ) = c 31 + d ( 1 , {   } ) = 7 + 5 = 12 ( 3 → 1 ) d(3, \{1\})= c_{31}+d(1, \{\ \})=7+5=12(3→1) d(3,{1})=c31+d(1,{ })=7+5=12(31)

    d ( 3 , { 2 } ) = c 32 + d ( 2 , {   } ) = 5 + 6 = 11 ( 3 → 2 ) d(3, \{2\})= c_{32}+d(2, \{\ \})=5+6=11(3→2) d(3,{2})=c32+d(2,{ })=5+6=11(32)

    (反过来思考,求从1出发,经过2、3,考虑到所有情况就是先要知道

    从2出发,经过3;或从3出发,经过2。同理,另外两种情况一样考虑)

  3. 再求解下一个阶段的子问题,有:
    d ( 1 , { 2 , 3 } ) = m i n { c 12 + d ( 2 , { 3 } ) ,   c 13 + d ( 3 , { 2 } ) } = m i n { 2 + 5 , 3 + 11 } = 7 ( 1 → 2 ) d(1, \{2, 3\})=min\{c_{12}+d(2,\{3\}), \ c_{13}+ d(3,\{2\})\}=min\{2+5, 3+11\}=7(1→2) d(1,{2,3})=min{c12+d(2,{3}), c13+d(3,{2})}=min{2+5,3+11}=7(12)
    d ( 2 , { 1 , 3 } ) = m i n { c 21 + d ( 1 , { 3 } ) ,   c 23 + d ( 3 , { 1 } ) } = m i n { 4 + 6 , 2 + 12 } = 10 ( 2 → 1 ) d(2, \{1, 3\})=min\{c_{21}+d(1, \{3\}), \ c_{23}+d(3, \{1\})\}=min\{4+6, 2+12\}=10(2→1) d(2,{1,3})=min{c21+d(1,{3}), c23+d(3,{1})}=min{4+6,2+12}=10(21)
    d ( 3 , { 1 , 2 } ) = m i n { c 31 + d ( 1 , { 2 } ) ,   c 32 + d ( 2 , { 1 } ) } = m i n { 7 + 8 , 5 + 9 } = 14 ( 3 → 2 ) d(3, \{1, 2\})=min\{c_{31}+d(1, \{2\}),\ c_{32}+ d(2, \{1\})\}=min\{7+8, 5+9\}=14(3→2) d(3,{1,2})=min{c31+d(1,{2}), c32+d(2,{1})}=min{7+8,5+9}=14(32)

    (反过来思考,求0经过1、2、3,考虑到所有情况就是先要知道

    从1出发,经过2、3;或从2出发,经过1、3;或从3出发,经过1、2)

  4. 直到最后一个阶段,有:
    d ( 0 , { 1 , 2 , 3 } ) = m i n { c 01 + d ( 1 , { 2 , 3 } ) ,   c 02 + d ( 2 , { 1 , 3 } ) , c 03 + d ( 3 , { 1 , 2 } ) } = m i n { 3 + 7 , 6 + 10 , 7 + 14 } = 10 ( 0 → 1 ) d(0, \{1, 2, 3\})=min\{c_{01}+ d(1, \{ 2, 3\}), \ c_{02}+ d(2, \{1, 3\}), c_{03}+ d(3, \{1, 2\})\}\\ =min\{3+7, 6+10, 7+14\}=10(0→1) d(0,{1,2,3})=min{c01+d(1,{2,3}), c02+d(2,{1,3}),c03+d(3,{1,2})}=min{3+7,6+10,7+14}=10(01)

    (反过来思考,这题就是求从0出发,经过中间点1、2、3)

    所以,从顶点0出发的TSP问题的最短路径长度为10,再将状态进行回溯,得到最短路径是0→1→2→3→0。图示如下:


2.分支限界法

题目重抄一下: ( ∞    3    6    7 5    ∞    2    3 6    4    ∞    2 3    7    5    ∞ ) \begin{pmatrix}\infty\ \ 3\ \ 6\ \ 7\\5\ \ \infty\ \ 2\ \ 3\\6\ \ 4\ \ \infty\ \ 2\\3\ \ 7\ \ 5\ \ \infty \end{pmatrix}   3  6  75    2  36  4    23  7  5  

一般情况下,假设当前已确定的路径为U=(r1, r2, …, rk),即路径上已确定了k个顶点,此时,该部分解的目标函数值的计算方法如下:

l b = ( 2 ∑ i = 1 k − 1 c [ r i ] [ r i + 1 ] + ∑ r i ∈ U r i 行 不 在 路 径 的 最 小 元 素 + ∑ r j ∉ U r j 行 最 小 的 两 个 元 素 ) / 2 lb=(2\sum_{i=1}^{k-1}{c[r_i][r_{i+1}]+\sum_{r_i\in U}{r_i行不在路径的最小元素}}+\sum_{r_j\notin U}{r_j行最小的两个元素})/2 lb=(2i=1k1c[ri][ri+1]+riUri+rj/Urj)/2

(这个公式理解为:每个城市一进一出都取最小的路,每个城市都选,重复了一遍,所以除以二)

从根结点开始依次计算目标函数值加入待处理结点表中直至叶子结点

算法步骤:

  1. 根据限界函数计算目标函数的下界10;采用贪心法得到上界10;

    (下界:由lb的求解公式,每个节点一进一出都取最小的,相加除以二,所以[(3+3)+(2+3)+(2+2)+(2+3)]/2=10;上界:由贪心法,每次都取最近的路径到下一节点,除了已经经过的节点,初1->2(3最小),再2->3(2最小),再3->4(2最小,且只能到4),最后4->1(3)回起点,3+2+2+3=10)

  2. 计算根结点的目标函数值并加入待处理结点表PT;

  3. 循环直到某个叶子结点的目标函数值在表PT中取得极小值
    3.1 i = 表PT中具有最小值的结点;
    3.2 对结点i的每个孩子结点x执行下列操作:
    3.2.1 估算结点x的目标函数值lb;
    3.2.2 若(lb<=up),则将结点x加入表PT中;
    否则丢弃该结点;

  4. 将叶子结点对应的最优值输出,回溯求得最优解的各个分量;

题解二叉树:
对于每一个子问题,就是把对应最小的路径替换掉,比如:第4子问题,把从1出替换成1->4,即3替换成了7,其他不变,算得是12

注意:无向图的TSP就直接对于每一个节点,取两个最小的无向路劲

例:下界用限界求得14,上界用贪心求得是16,其他步骤同上


3.回溯法

对于TSP问题,回溯法最后构造的是横向的排列树,如下,解的个数是n!

题目重抄一下: ( ∞    3    6    7 5    ∞    2    3 6    4    ∞    2 3    7    5    ∞ ) \begin{pmatrix}\infty\ \ 3\ \ 6\ \ 7\\5\ \ \infty\ \ 2\ \ 3\\6\ \ 4\ \ \infty\ \ 2\\3\ \ 7\ \ 5\ \ \infty \end{pmatrix}   3  6  75    2  36  4    23  7  5  

实际画出的解空间树就是上上图n=4的解空间树,边代表问题中的节点,每种情况都走一遍,但一种情况走不通时或不满足条件时,就换兄弟节点走。较为繁琐,略。

  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
TSP问题是指旅行商问题,即在给定的一些城市中,旅行商要找到一条路径,使得他可以从一个城市出发,经过所有城市,最后回到起点,并且要求路径的总长度最小。分支限界法是一种解决TSP问题的有效方,其中优先队列式分支限界法是其中的一种实现方式。 优先队列式分支限界法将活结点表按照某个估值函数C(x)的值组织成一个优先队列,并按优先队列中规定的结点优先级选取优先级最高的下一个结点成为当前扩展结点。在TSP问题中,每个节点表示一个城市,记录了从树的根节点(即起始点)出发到该城市的一条路径。使用优先队列来存储节点,节点的优先级为该条路径最终费用的下界,这个下界为当前费用加上还没有经过的点的最小出边费用之和。在更新一个节点后,如果发现只差一个点就能够遍历全部点时,该节点的费用加上到达最后一个点的费用,再加上最后一个点到初始节点的费用,就是路径总费用,可以尝试更新最优解。当从优先级队列中取出的节点为叶子节点时,就找到了最优解。 下面是使用Python实现优先队列式分支限界法求解TSP问题的代码示例: ```python import heapq def tsp(graph, start): n = len(graph) visited = set([start]) heap = [(0, start, visited)] while heap: (cost, node, visited) = heapq.heappop(heap) if len(visited) == n: return cost + graph[node][start] for neighbor, distance in enumerate(graph[node]): if neighbor not in visited: new_cost = cost + distance new_visited = visited | set([neighbor]) lower_bound = new_cost + min(graph[neighbor]) * (n - len(new_visited)) heapq.heappush(heap, (lower_bound, neighbor, new_visited)) # 示例 graph = [[0, 2, 9, 10], [1, 0, 6, 4], [15, 7, 0, 8], [6, 3, 12, 0]] start = 0 print(tsp(graph, start)) # 输出:21 ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

空名_Noname

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值