zoukankan      html  css  js  c++  java
  • 物流运输-最小化门店个数问题

    例如,有一批食材要发到肯德基门店,分别分配给了2个司机去送货,如下: 

    都从上海出发
    2个司机
    
    第一个司机:
    	苏州	新苏站餐厅、园区车坊餐厅
    	无锡	高铁无锡东站餐厅、无锡城际餐厅
    
    
    第二个司机:
    	无锡	海岸城餐厅、无锡城际餐厅、大润发 餐厅
    	常州	常州百货大楼餐厅、常州城际 餐厅  

    某位调度大哥一看,都经过无锡,还都要往“无锡城际餐厅”送货,感觉重复了,不能合并?现在2位司机的送货门店个数分别是4个门店以及5个门店,能不能缩减下(由于发现了公共门店,因此缩减门店数变成了可能)

    对于这个问题,我们首先不考虑货物能不能装上同一辆车这种容量问题,先考虑门店合并问题,其次考虑容量问题。此文中只说门店合并问题。

    和上篇的风格一样,先贴出我们期望的output:

    ------------原始组合-------------
    第一个司机:       4个门店              full: 新苏站餐厅,园区车坊餐厅,高铁无锡东站餐厅,无锡城际餐厅,      fixed: 新苏站餐厅,园区车坊餐厅,      dynamic: 高铁无锡东站餐厅,无锡城际餐厅,
    第二个司机:       5个门店              full: 常州百货大楼餐厅,常州城际 餐厅,海岸城餐厅,无锡城际餐厅,大润发 餐厅,      fixed: 常州百货大楼餐厅,常州城际 餐厅,      dynamic: 海岸城餐厅,无锡城际餐厅,大润发 餐厅,
    -------------移动组合-------------
    第一个司机(5个门店):新苏站餐厅, 海岸城餐厅, 高铁无锡东站餐厅, 园区车坊餐厅, 大润发 餐厅,      第二个司机(3个门店):常州城际 餐厅, 无锡城际餐厅, 常州百货大楼餐厅, 
    从第一个司机move到第二个司机的:无锡城际餐厅, 从第二个司机move到第一个司机的:海岸城餐厅, 大润发 餐厅, 
    
    第一个司机(3个门店):新苏站餐厅, 无锡城际餐厅, 园区车坊餐厅,      第二个司机(5个门店):常州城际 餐厅, 海岸城餐厅, 高铁无锡东站餐厅, 常州百货大楼餐厅, 大润发 餐厅, 
    从第一个司机move到第二个司机的:海岸城餐厅, 从第二个司机move到第一个司机的:无锡城际餐厅, 
    
    第一个司机(5个门店):新苏站餐厅, 海岸城餐厅, 无锡城际餐厅, 园区车坊餐厅, 大润发 餐厅,      第二个司机(3个门店):常州城际 餐厅, 高铁无锡东站餐厅, 常州百货大楼餐厅, 
    从第一个司机move到第二个司机的:海岸城餐厅, 从第二个司机move到第一个司机的:海岸城餐厅, 无锡城际餐厅, 大润发 餐厅, 
    
    第一个司机(3个门店):新苏站餐厅, 海岸城餐厅, 园区车坊餐厅,      第二个司机(5个门店):常州城际 餐厅, 高铁无锡东站餐厅, 无锡城际餐厅, 常州百货大楼餐厅, 大润发 餐厅, 
    从第一个司机move到第二个司机的:海岸城餐厅, 无锡城际餐厅, 从第二个司机move到第一个司机的:海岸城餐厅, 
    
    第一个司机(3个门店):新苏站餐厅, 园区车坊餐厅, 大润发 餐厅,      第二个司机(5个门店):常州城际 餐厅, 海岸城餐厅, 高铁无锡东站餐厅, 无锡城际餐厅, 常州百货大楼餐厅, 
    从第一个司机move到第二个司机的:海岸城餐厅, 无锡城际餐厅, 从第二个司机move到第一个司机的:大润发 餐厅, 
    
    -------------SUMMARY-------------
    OPTIMAL
    有效移动组合个数:5  

     解题思路:

    首先判读这个问题的类型,目测来看数据量较小,不存在穷举非常耗时这种问题,因此首选采用确定性算法,而不是非确定性算法(遗传算法、粒子算法这种是非确定的,每次执行都会变,特别是数据量大的时候)

    既然选择确定性算法&&数据量小,因此就穷举组合了,按照上面的城市组合,又分成了固定与动态的城市区分。固定代表这个城市内的门店是不可调整的,动态代表这个城市内的门店是可调整的,可调整代表可以与其他司机的同城市的门店进行互换操作,其实区分固定与动态城市后,算法的数据量会进一步减小,因为只要穷举动态城市部分就行了。

    public static void main(String[] args) {
    
            List<ReceiverItem> leftItems=generateData(ListUtils.newList("新苏站餐厅", "园区车坊餐厅"), ListUtils.newList("高铁无锡东站餐厅", "无锡城际餐厅"));
            List<ReceiverItem> rightItems=generateData(ListUtils.newList("常州百货大楼餐厅", "常州城际 餐厅"), ListUtils.newList("海岸城餐厅", "无锡城际餐厅", "大润发 餐厅"));
    
    
            List<IntVar> leftFixedVars=new ArrayList<>();
            List<IntVar> leftExchangableVars=new ArrayList<>();
            List<IntVar> rightFixedVars=new ArrayList<>();
            List<IntVar> rightExchangableVars=new ArrayList<>();
    
            CpModel model = new CpModel();
    
            //第一个司机
            for(ReceiverItem receiverItem:leftItems)
            {
                if(!receiverItem.exchangable)
                {
                    //不可以交换,因此固定为第一个司机
                    IntVar var=model.newConstant(1);
                    leftFixedVars.add(var);
                }
                else
                {
                    IntVar var=model.newIntVar(1, 2, "");
                    leftExchangableVars.add(var);
                }
            }
            //第二个司机
            for(ReceiverItem receiverItem:rightItems)
            {
                if(!receiverItem.exchangable)
                {
                    //不可以交换,因此固定为第二个司机
                    IntVar var=model.newConstant(2);
                    rightFixedVars.add(var);
                }
                else
                {
                    IntVar var=model.newIntVar(1, 2, "");
                    rightExchangableVars.add(var);
                }
            }
    
            VarArraySolutionPrinter varArraySolutionPrinter=new VarArraySolutionPrinter(leftItems, rightItems, leftFixedVars, leftExchangableVars, rightFixedVars, rightExchangableVars);
    
            CpSolver solver = new CpSolver();
    
            System.out.println("------------原始组合-------------");
            PrintUtils.display组合("第一个司机:", leftItems);
            PrintUtils.display组合("第二个司机:", rightItems);
    
            System.out.println("-------------移动组合-------------");
    
            CpSolverStatus status=solver.searchAllSolutions(model, varArraySolutionPrinter);
    
            System.out.println("-------------SUMMARY-------------");
    
            System.out.println(status);
    
            List<MoveAction> moveActions=varArraySolutionPrinter.getMoveActions();
            System.out.println("有效移动组合个数:"+moveActions.size());
        }
    
    
    
        static class VarArraySolutionPrinter extends CpSolverSolutionCallback {
            private List<ReceiverItem> leftItems;
            private List<ReceiverItem> rightItems;
            private List<IntVar> leftFixedVars;
            private List<IntVar> leftExchangableVars;
            private List<IntVar> rightFixedVars;
            private List<IntVar> rightExchangableVars;
            private List<MoveAction> moveActions=new ArrayList<>();
    
            public List<MoveAction> getMoveActions()
            {
                return this.moveActions;
            }
    
            public VarArraySolutionPrinter(List<ReceiverItem> leftItems, List<ReceiverItem> rightItems, List<IntVar> leftFixedVars, List<IntVar> leftExchangableVars, List<IntVar> rightFixedVars, List<IntVar> rightExchangableVars) {
                this.leftItems=leftItems;
                this.rightItems=rightItems;
                this.leftFixedVars=leftFixedVars;
                this.leftExchangableVars=leftExchangableVars;
                this.rightFixedVars=rightFixedVars;
                this.rightExchangableVars=rightExchangableVars;
            }
    
            @Override
            public void onSolutionCallback() {
                Set<String> leftReceivers=new HashSet<>();
                Set<String> rightReceivers=new HashSet<>();
    
                List<String> originalleft=new ArrayList<>();
                List<String> move2left=new ArrayList<>();
    
                List<String> originalright=new ArrayList<>();
                List<String> move2right=new ArrayList<>();
    
                //left fixed
                for(int idx=0;idx<leftFixedVars.size();idx++)
                {
                    leftReceivers.add(leftItems.get(idx).name);
                }
                //left exchangable
                for(int idx=0;idx<leftExchangableVars.size();idx++)
                {
                    IntVar var=leftExchangableVars.get(idx);
                    long v=value(var);
                    if(v==1)
                    {
                        leftReceivers.add(leftItems.get(idx+leftFixedVars.size()).name);
                        originalleft.add(leftItems.get(idx+leftFixedVars.size()).name);
                    }
                }
                for(int idx=0;idx<rightExchangableVars.size();idx++)
                {
                    IntVar var=rightExchangableVars.get(idx);
                    long v=value(var);
                    if(v==1)
                    {
                        leftReceivers.add(rightItems.get(idx+rightFixedVars.size()).name);
                        move2left.add(rightItems.get(idx+rightFixedVars.size()).name);
                    }
                }
    
                //right fixed
                for(int idx=0;idx<rightFixedVars.size();idx++)
                {
                    rightReceivers.add(rightItems.get(idx).name);
                }
                //right exchangable
                for(int idx=0;idx<leftExchangableVars.size();idx++)
                {
                    IntVar var=leftExchangableVars.get(idx);
                    long v=value(var);
                    if(v==2)
                    {
                        rightReceivers.add(leftItems.get(idx+leftFixedVars.size()).name);
                        move2right.add(rightItems.get(idx+rightFixedVars.size()).name);
                    }
                }
                for(int idx=0;idx<rightExchangableVars.size();idx++)
                {
                    IntVar var=rightExchangableVars.get(idx);
                    long v=value(var);
                    if(v==2)
                    {
                        rightReceivers.add(rightItems.get(idx+rightFixedVars.size()).name);
                        originalright.add(rightItems.get(idx+rightFixedVars.size()).name);
                    }
                }
    
                if(leftReceivers.size()<=5&&rightReceivers.size()<=5&&(leftReceivers.size()<=3||rightReceivers.size()<=3))//最终穷举出来的要满足的约束
                {
                    if(move2left.size()>0&&move2right.size()>0) {
                        PrintUtils.displayReceivers(leftReceivers, rightReceivers, "");
                        PrintUtils.displayActions(originalleft, move2left, originalright, move2right);
    
                        MoveAction moveAction = new MoveAction();
                        moveAction.setMove2Left(move2left);
                        moveAction.setMove2Right(move2right);
                        moveActions.add(moveAction);
                    }
                }
            }
        }
    

      

  • 相关阅读:
    git的使用
    免安装版mySQL的安装及配置
    Eclipse中安装freemarker插件
    freemarker配置
    Matlab机器人工具箱安装教程
    书籍推荐
    电影推荐
    自走棋地精猎玩法
    wineqq中接收文件的查看与移动
    windows和linux键值表
  • 原文地址:https://www.cnblogs.com/aarond/p/logistics-elimination.html
Copyright © 2011-2022 走看看