物流运输-最小化门店个数问题

例如,有一批食材要发到肯德基门店,分别分配给了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);
                }
            }
        }
    }

  

 

posted @ 2020-08-15 12:31  McKay  阅读(293)  评论(0编辑  收藏  举报