快递、拆分、合并、优选逻辑

  

需求:

  • 根据规则 分配 物品到不同的包裹里。
  • 有些可以放在同一包裹有一些不能。
  • 可以发同一物流的可以放到一个包裹,不同物流的包裹有不同的重量限制(也有可能没有限制)、某些物品在某些物流渠道有单个包裹同种物品的数量限制。

比如跨境物流危险品限制:

危险品类型:配套电、内置电、纯电、移动电源(外置电)、强磁、弱磁、液体、膏体、指甲油、假发、喷雾、粉末、种子、唇彩、唇膏、面膜、指甲胶
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();

        }


    }

还有一些其他逻辑不是通用的就不贴了,花了一天时间才写完。。。还没有来及测试。

 参考:背包问题

原文地址:https://www.cnblogs.com/zhuwansu/p/10187051.html