需求:
- 根据规则 分配 物品到不同的包裹里。
- 有些可以放在同一包裹有一些不能。
- 可以发同一物流的可以放到一个包裹,不同物流的包裹有不同的重量限制(也有可能没有限制)、某些物品在某些物流渠道有单个包裹同种物品的数量限制。
比如跨境物流危险品限制:
危险品类型:配套电、内置电、纯电、移动电源(外置电)、强磁、弱磁、液体、膏体、指甲油、假发、喷雾、粉末、种子、唇彩、唇膏、面膜、指甲胶
1107 - 飞特泰邮:内置电、膏体(单个包裹不超一个)、粉末(单个包裹不超一个)、种子、唇彩、唇膏、面膜、指甲胶 1106 - 快飞鱼敏感货K邮宝:配套电、液体(单个包裹不超一个)、指甲油(单个包裹不超两个) 1100 - 快飞鱼荷邮敏感货:配套电、纯电、移动电源(外置电)、液体(单个包裹不超四个)、指甲油(单个包裹不超三个)、喷雾(单个包裹不超两个) 1051 - 递四方新加坡小包:内置电、弱磁 1034 - 出口易荷兰小包:内置电、弱磁 1040 - 出口易大陆E邮宝:假发 1029 - 出口易省外E邮宝:假发 1026 - 出口易大陆DHL:假发 3 - DHL:假发 19 - 新加坡DHL:假发
要求:
运费最低。(根据物品的重量和订单信息可以预估运费。)
求 最佳分包。
思路:
1、穷举所有规则。
2、穷举所有适配规则的物品(我叫这个是 成包策略 g2p 策略)
- 按重量拆分。(也存在一套穷举优选的逻辑在,和策略优选的逻辑差不多)
3、穷举所有策略组合。
- 过滤组合中所有物品和订单物品不匹配的组合。
4、转换为【策略组】组合。(既【策略】组合 变成 【策略组】组合)策略组 指 同渠道的策略。设 策略为 A 、策略组为 B{ A[] } 有 A[] => B[] 其中 All A In B[] = All A in A[] 。
5、策略组 快递竞价。每一个策略组 计算其中所有物品的重量 ,然后计算运费。
6、优选【策略组组合】。全部物品总运费最低的 策略组组合。
7、一个策略组 成一个包。
穷举所有组合的函数:
public static List<T[]> GetAllComb<T>(T[] arr, Func<T[], bool> filter) { var res = new List<T[]>(); int nCnt = arr.Length; //int nBit = (0xFFFFFFFF >>> (32 - nCnt)); int nBit = 1 << nCnt; for (int i = 1 ; i <= nBit ; i++) { var item = new List<T>(); for (int j = 0 ; j < nCnt ; j++) { if ((i << (31 - j)) >> 31 == -1) { item.Add(arr[j]); } } T[] itemArr = item.ToArray(); if (filter != null) { if (filter(itemArr)) { res.Add(itemArr); } } else { res.Add(itemArr); } } return res; }
物品根据重量拆分优选代码:
//超重拆分生成多个策略。默认的拆分的策略是单包 1900g。 /// <summary> /// 物品超重拆分策略 /// 默认步长是 1900g /// 按最小包裹数优先拆分 /// </summary> public class GoodsOverLoadSpiltStrategy { private const int SPLITSTEP = 1900; private int splitStep; public GoodsOverLoadSpiltStrategy(int splitStep = SPLITSTEP) { this.splitStep = splitStep; } internal List<Purchase_Goods[]> Spilt(List<Purchase_Goods> goodsList) { var newPackage = new List<Purchase_Goods>(); //从所有【物品中】获取所有小于 1900 的组合 var combs = CombinationAlgorithm.GetAllComb(goodsList.ToArray(), goods => { return goods.Sum(m => m.Weight) <= 1900; }); //从所有【1900 组合中】获取等于总物品的组合 var res = CombinationAlgorithm.GetAllComb(combs.ToArray(), comb => { var list = comb.SelectMany(m => m).ToList(); return list.All(goodsList.Contains) && list.Count == goodsList.Count; }); //返回最佳组合 return res.OrderByDescending(m => m.Count()).FirstOrDefault().ToList(); } }
还有一些其他逻辑不是通用的就不贴了,花了一天时间才写完。。。还没有来及测试。
参考:背包问题