求点拨: N 个商品, M 种发货渠道,寻找最优解?

2018-05-23 14:39:56 +08:00
 timchou
实际中遇到一个实际场景,想了半天没想到合适的方式,有没有算法达人点拨下?

场景是电商发货中,每个商品都有多种的发货渠道,每种渠道的价格不同,然后还有各种包裹限制,所以需要综合判断,选择一个最优的发货方式:

1.有 n 个商品,每个商品有:
a.价格 price
b.重量 weight
c.税率 tax

2.有 m 种渠道,每个渠道都有如下几个属性:
a.首重成本 x 元(假设首重指的是 1kg)
b.续重成本 y 元 /kg
c.单个包裹重量上限 L1
d.单个包裹价值上限 L2
e.单个包裹税金上限 L3

现在要对这些商品进行拆分,寻找最优拆分方式,要求:
1.成本价最低
2.单个包裹不能超过上述的限制 L1\L2\L3,也就是说一旦超过后,则需要另外起一个包裹。


最简单的方式是把所有的可能性都摆出来,然后一一计算,选一个最优的,但是 n 和 m 一多的话,计算量就很大。。

不知道有什么合适的算法可以处理这种问题吗?

ps1:
之前还想这么做:m 个渠道就是 m 个 slot,然后对每个商品,计算该商品丢到各个 slot 后,总的成本价分别是多少,然后选择一个最便宜的丢进去,但是实际上这个每个渠道是由首重+续重来确定费用的,因此商品丢到这个 slot 后,可能当前是最便宜的,但是最终结果不一定,比如渠道 1:首重很便宜,但是续重很贵;渠道 2:首重很贵,但是续重很便宜。。
2711 次点击
所在节点    程序员
24 条回复
746970179
2018-05-23 16:26:36 +08:00
之前做过类似的.
解决思路是: 为每个渠道计算价格
解决方案:
为渠道建表, 将首重, 首重费, 续重单位, 续重费用, 重量限制等当作字段, 保存起来
然后写一个方法, 方法的工作内容是: 传入渠道数据, 和商品重量, 计算出金额

这个公式的难点是, 不同的渠道, 不是所有的都是统一的公式, 有的可能没有首重费用, 有的可能有折扣等等
实际情况中, 不太可能用一个公式保存
所以根据实际情况, 抽象出几个公式即可
我之前做的时候, 总共用了三个公式:
1.线性增长(类似买菜, 精确到克) a+kx (a 是固定费用, k 是每 kg 多少钱, x 是重量)
2.均匀阶梯增长(通话计费, 每 1 分钟固定 1 毛钱这样, 不足一分钟照 1 分钟算)
3.不均匀阶梯(不规律的计费, 可能 1kg 的包裹 10 元, 2kg 的包裹 11 元, 3kg 的包裹 20 元这样, 无规律)
其中 1 和 2, 可以用同一个公式或者分开, 因为 1 就是单位重量为 1g 的均匀阶梯增长
3 的话, 看起来麻烦, 其实最简单, 一个字段, 用 json 存起来就行, 到时候按表查价格即可

整理好后, 就能用方法, 为一个商品计算每个物流方式的准确价格了

但实际情况比这还会复杂很多:
1. 各种折扣: 首重折扣, 续重折扣, 总价折扣, 地区折扣等
2. 地区价格: 发往每个地区的价格可能都有变化, 这是一个坑, 整理起来比较费时费力
3. 商品的多仓库发货, 拆包发货. 这个也很麻烦和复杂. 不过主要看业务需求
4. 维护问题.
5. 性能相对来说不是大问题.

最后效果的话, 如果结合实际业务需求做出来, 便宜 5~10%问题不大
timchou
2018-05-23 16:35:15 +08:00
@746970179 很感谢!

您说的:“整理好后, 就能用方法, 为一个商品计算每个物流方式的准确价格了 ”

这点貌似在我说的场景里不能适用,因为对于某个渠道,一件商品和 N 件商品最后的运费是不一样的,因为渠道有首重和续费

比如某个渠道,首重很贵,续重便宜,另外有的渠道首重很便宜,续重很贵。。这种情景就很复杂了。
menc
2018-05-23 17:03:16 +08:00
典型线性规划问题
先写出来标准型,然后直接传入 scipy 求解线性规划问题
menc
2018-05-23 17:04:52 +08:00
简单点说
你的目标函数 F 是一个线性函数,目标是最大化或者最小化这个目标函数
你的若干约束都是线性不等式。
存在有限个参数。
那八九不离十就是线性规划问题
wplct
2018-05-23 17:14:22 +08:00
额。还要多个商品打包么
zjsxwc
2018-05-23 17:16:38 +08:00
一个商品允许通过 2+个渠道发货吗
746970179
2018-05-23 17:25:33 +08:00
@timchou
是表述的不准确, 应该是包裹. 是为每个包裹的重量进行计算
我说的那个方法, 传入的参数是重量, 和物流方式的相关计价参数
因此, 是商品还是包裹, 问题不大, 最终传入方法的参数类型不变
takato
2018-05-23 17:25:40 +08:00
NP-Complete
746970179
2018-05-23 17:29:45 +08:00
@zjsxwc
这是我的表述不清, 准确的说是一个包裹. 这个就可能包含多件商品了
yesterdaysun
2018-05-23 17:48:22 +08:00
做过类似的, 我的解决方案是:
1. 快递费模块, 负责计算一个包裹用特定的仓库特定的渠道, 发特定的地区, 精确的价格是多少, 需要事先把所有需要的规则和价格设置放进系统
2. 规则模块, 负责判断所有仓库和渠道的规则, 比如某个渠道不发偏远的地区等等
3. 包裹模块, 负责生成包裹方案, 就是几个包裹, 每个里面放那些产品 /数量, 贪心算法, 从一整个包裹开始算, 每个仓库, 每个渠道这样算, 利用规则模块排除不要的选项, 如果不行就拆包, 就是简单的求 subset 的算法, 一点点拆开穷举

实际情况是大部分情况一个包裹就搞定了, 少部分一般拆两个包裹也搞定了, 不过如果订单产品数量多的情况下, 拆包穷举的数量是惊人的, 所以我直接就写死试了多少次就直接结束报错等人工处理了, 不过应该还没有遇到这个情况.

你可以根据自己的情况改进
tedzhu
2018-05-23 17:58:09 +08:00
感觉确实是 NP 完全 要搜索+尽量剪枝吧 先分到每个 slot 里再在每个 slot 里排列 另外考虑实际情形 m 会不会不大 m<5? 也许没那么糟糕
如果 n 比较大 可以考虑先排序 再采用若干策略求近似解 取最好的
zynlp
2018-05-23 17:59:16 +08:00
云开发🤣
timchou
2018-05-23 18:07:23 +08:00
谢谢各位提供的思路,我好好研究学习学习,谢谢啦


@menc
@746970179
@takato
@yesterdaysun
@tedzhu
Fulcrum
2018-05-23 18:17:39 +08:00
有一个我能回答的问题,百度运筹学-运输问题。
Fulcrum
2018-05-23 18:20:19 +08:00
找一个运筹学课本看一下,运输问题基本都会提出来讲
stevenbipt
2018-05-23 18:34:39 +08:00
典型的运筹学问题
takato
2018-05-23 18:38:25 +08:00
@timchou 首先不建议直接将 X 和 Y 扔进黑箱训练,这样可能能得到一个局部最优解。
虽然很多时候八九不离十,但是当物品增多的时候有可能翻车。
geelaw
2018-05-23 18:43:03 +08:00
可以表达为 0-1 规划问题(当然这是平凡的……因为 0-1 规划是 NPC ),应该说可以很自然地表达为 0-1 规划问题。

每个渠道最多发 n 个包裹,把它看成 mn 个包裹(每个渠道复制 n 份),对每个商品设置 mn 个变量,表示“是否通过这个包裹发送”,对每个包裹设置一个变量,表示“是否有包裹”。

约束是:

每个商品的各个变量和是 1 (恰好发送一次)
每个包裹的“是否有”乘 n 不小于发入这个包裹的商品数
每个包裹费用 不小于 是否有*首重
每个包裹费用 不小于 是否有*首重 + (总重-1)*续重
每个包裹总重约束
每个包裹价值约束
每个包裹税金约束

最小化 费用之和

具体到求解,可以用分支定界法等。

该问题是 NPH,因此很难想象到会有多项式时间的算法;尚不清楚这个问题是否是 strongly NPC,可以尝试寻找伪多项式时间的算法。
oswuhan
2018-05-23 18:53:05 +08:00
哈哈,考验数学功底的时候到了
daveze
2018-05-23 19:29:07 +08:00
我来个比较暴力的方案. 假设商品的价格 和 重量都是可以通过范围来枚举的.
比如 价格 (1 元,2 元),(2 元,3 元),(1001 元,1002 元)
重量 (100g, 110g), (110g, 120g)
这样价格和重量的枚举范围是可以进行组合. 比如
(1 元-2 元, 100g-110g), (1 元-2 元, 110g-120g), xxxx
这样我们可以预先计算好每个组合最适合的渠道,如下:
(1 元-2 元, 100g-110g, 渠道 2), (1 元-2 元, 110g-120g, 渠道 3), xxxx

要计算一个商品的最佳渠道, 就是在简单的在上述范围内去查找最接近的一个组合(通过 R+tree).
注意: 如果商品的价格或者重量超过了上面枚举的范围, 再退化到 n * m 的计算方案

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/457149

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX