tsp的理论和实践(8)派件时间窗和held-karp动态规划

tsp目录算法

  1. 最简单的实践 juejin.im/post/5d1b14…
  2. 最简单的理论 juejin.im/post/5d1b15…
  3. 当前tsp的现状 juejin.im/post/5d1b19…
  4. 单起点任务分配 juejin.im/post/5d1c6d…
  5. 多起点任务分配 juejin.im/post/5d1dbe…
  6. 更简洁的多起点分配 juejin.im/post/5d1dc2…
  7. 起点时间窗 juejin.im/post/5d1f1f…
  8. 终点时间窗和hk juejin.im/post/5d1f44…
  9. LK简介 juejin.im/post/5d25b8…
  10. tsp系列暂停一下 juejin.im/post/5d302e…

tsp领域的问题, 并不都是tsp问题, 可是, tsp相关的算法通常都能解决, 只要你能为某一个充满个性的问题儿子找到他亲生的解决方案爸爸.数组

通过前面7篇的努力, 咱们实际上已经解决了订单分配问题, 由于派件时间窗其实不是一个分配问题. 下面咱们详细分析一下bash

需求概述
  1. 某样物品, 客户要求在下午4:00前收到.
  2. 某样物品, 客户要求在中午12:00前收到.
分析
  • 这些其实并非需求, 缘由是: 咱们没法保证知足, 除非用相似无人机这样的设备, 直接空投过去. 否则, 受各类因素干扰, 咱们通常状况下只能说, 预计某一天到达. 快递的目标就是把这个某一天尽可能提早, 好比全球第二天达.
  • 而后, 当单量上升到必定地步的时候, 咱们能够把工做时间段逐步拆碎, 好比天天分红3段, 这个货预计上午9:00-12:00到. 单量再上升, 甚至能够半个小时一段. 好比配餐服务.
  • 若是客人必定要求咱们更快速配送, 好比支付不少费用, 那么能够经过路线调整来知足.
  • 可是, 实际上配送效率仍是咱们服务的总体质量中最核心的内容, 所以, 咱们应该针对全部客户给一个至关快的配送效率, 而不是针对某些客户提供付费服务.
结论
  • 咱们应该提供更高效的服务.
  • 好比当日达, 咱们要保证当日能到达, 而且当日能让尽可能多的订单到达.
  • 由此, 线路规划仍是很是有用的. 并且有与实际工做中咱们的订单有诸多的限制, 所以, 这个线路规划不能使用生成类方法好比:
    • 插入类算法, 如: 最远插入法…...
    • 生成树类算法, 包括christofides
  • 可使用尝试类算法例如
    • 线性规划LP
    • LK交换算法
    • 遗传算法
    • 动态规划
  • 这些算法里面, LP, LK和遗传咱们后文讨论, 这里咱们先聊一下动态规划.
动态规划 held-karp算法

这个算法很优雅, 也是目前精确算法中理论速度最好的, 惋惜的是, 他的开销是2的n次方. 因此, 他不实用, 很遗憾, 我试过了, 确实不实用, 可是他的思路对咱们仍是有不少启发的.数据结构

  • 每一步都计算全部的点位最后一个点的可能性.
  • 每一步都依赖前一步的结果.

例如ide

  • 一共有10个点.
  • 假设如今是第六步,
    • 我要计算4为最后一步的全部结果.
    • 那么, 以 1, 2, 3, 5, 6, 7, 8, 9, 10为最后一个点的5个点的集合, 而且是不包含4的集合.
    • 而后能够获得以4为终点的全部含有6个点的结果.

整体思路post

  • 关键是编码规则. 建议规则ui

    _id1_id2_id3_
    复制代码
  • 好比已经生成了3个元素的全部集合.编码

  • (1, 2, 3) 这三个元素的集合能够顺序生成,spa

    • ((1, 2, 3,) 4,) , ((1, 2, 3,) 5,) , ((1, 2, 3,) 6,)…… 等等.
  • 而后同理(1, 2, 4), 能够顺序生成 ((1, 2, 4,) 3,),3d

  • ((1, 2, 3,) 4,) 和 ((1, 2, 4,) 3,) 都是(1,2,3,4)的一部分, (1,2,3,4)包含了全部的状况.

时间开销: 以((1, 2, 3,) 4,)举例, 最后一步.

  1. (1, 2, 3) 这里是c43, 是四个挑3个. cnm, n是总数, m是当前的轮次.
  2. 而后, 和最后一个数字的结合是p42, 是排列, 4*3的排列=n * (n-1)

整体步骤

  • 初始化:

    • 生成(1), (2), (3),…….(10)

    • 生成((1), 2), ((1), 3)……((10),9)

    • 此时(1, 2), 包含((1), 2)和 ((2), 1)

    • 这里(1, 2)是一个karp, 他的id

      _id1_id2_
      复制代码
  • 实际运算

    • 生成(1, 2, 3), (1, 2, 4)……(8,9,10)

    • 顺序生成4个元素…...

    • 一直到所有10个元素的一个karp, 他的id:

      _id1_id2_id3_id4_id5_id6_id7_id8_id9_id10_
      复制代码
  • 数据定义

    • 全部的karp都在一个held结构里面.
    • 能够快速的索引到, 指望的karp, 若是对应的karp没有索引到, 就新建一个.

算法

  • 一个for循环
    • 每一个层次都处理当前层次的held结构.
    • 处理的过程当中生成下一个层次的held.

数据结构

  • held结构包含本层次的全部karp,
    • 好比held(2)包含全部的karp(1, 2), karp(1, 3)….. karp(9,10)
    • held里面能够顺序遍历本身的全部karp.
    • held能够索引本身的karp.
      • 如何索引到合适的karp.
      • 根据一组key数组, 索引到合适的karp.
      • 这一个数组key, 能够组合为一个字符串. 用这个串做为karp的key
  • karp
    • 插入
      • 插入某个包含key的值.
    • key, 总体包括全部key(element->e).
      • 包含的key,
        • 反正都要indexof, 不如就用array吧.
      • 不包含的key
function algorithm TSP (G, n)
  for k := 2 to n do
    C({k}, k) := d1,k
  end for

  for s := 2 to n-1 do
    for all S ⊆ {2, . . . , n}, |S| = s do
      for all k ∈ S do
        C(S, k) := minm≠k,m∈S [C(S\{k}, m) + dm,k]
      end for
    end for
  end for

  opt := mink≠1 [C({2, 3, . . . , n}, k) + dk,1]
  return (opt)
end
复制代码
相关文章
相关标签/搜索