Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 723|回复: 0

揽货最短路径解决方案算法 - C# 蚁群优化算法实现

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-5-2 13:39:28 | 显示全部楼层 |阅读模式

    需求为(自己编的,非实际项目):

    某配送中心进行揽货,目标客户数为50个客户,配送中心目前的运力资源如下:

    1. 现有车辆5台
    2. 单台运力最大行驶距离200千米
    3. 单台运力最大载重公斤1吨

    问:运力怎样走法才能以最低的成本完成针对这50个客户的揽货行为

    是个最优化问题(运筹学),我们只考虑简化后的模型,不考虑路面交通、时间窗口这些复杂计算,用蚁群优化算法来实现接近最优解的计算。

    关于蚁群优化算法的理论请看这篇文章:https://www.cnblogs.com/asxinyu/p/Path_Optimization_Tsp_Problem_Ant_System_CSharp.html

    里面的基本算法已经写明了,也有demo,本文是针对如何适应到具体业务的介绍(本文用的蚁群核心代码也是上文中改来的)

    蚁群主要步骤为:

    1. 初始化(如信息素)
    2. 开始迭代
      1. 构造各个蚂蚁,以及蚂蚁走的路径(核心是针对后续节点的SELECT)
      2. 计算适应度
      3. 加入优秀蚂蚁到跟踪列表
      4. 更新信息素(根据适应度)
    3. 结束迭代
    4. 给出报告

    原文章里用的是TSP做DEMO,比较难看清楚如何应用到实际业务逻辑中

    同样的,最困惑的核心中的核心,类似遗传算法,也是适应度值的计算,有的地方是一步一步增加vlaue,比如单纯距离的增加,但是复杂点的都没法这么操作,而是要看整体路径的指标(包括惩罚等)

    由于蚁群优化算法和本文代码都能下载,所以只介绍适应度value的计算

    下载

     

    class FitnessValueCalculator
        {
            private static int 拥有运力车辆数 = 5;
            private static int 单台运力最大行驶距离 = 200;
            private static int 单台运力最大载重公斤 = 1000;
            private static double 惩罚权重 = 20;
    
            public static double Calculator(ShortestDeliverAnt ant)
            {
                var paths = new List<string>();
    
                var distances = new List<double>();
                var weights = new List<double>();
    
                double 当前行驶距离 = 0;
                double 当前运力载重 = 0;
                string 当前行驶路径 = "";
                int 当前所需运力数 = 1;
    
                //计算枢纽到第一个客户配送距离
                当前行驶路径 += "HUB-->" + ant.PathNodes.First();
                当前行驶距离 += ant.DistanceHelper.hub.DistanceTo(ant.DistanceHelper.customers[ant.PathNodes.First()]);
                当前运力载重 += ant.DistanceHelper.customers[ant.PathNodes.First()].需求量_公斤;
    
                foreach (var path in ant.Edges)
                {
                    var fromNodeId = path.Key;
                    var toNodeId = path.Value;
    
                    var fromNode = ant.DistanceHelper.customers[fromNodeId];
                    var toNode = ant.DistanceHelper.customers[toNodeId];
    
                    double newAddedDistance2Customer = 0;
                    double newAddedDistance2Hub = 0;
                    double newAddedWeight = 0;
    
                    newAddedDistance2Customer = fromNode.DistanceTo(toNode);
                    newAddedDistance2Hub = toNode.DistanceTo(ant.DistanceHelper.hub);
    
                    newAddedWeight = toNode.需求量_公斤;
    
                    if (当前行驶距离 + newAddedDistance2Customer + newAddedDistance2Hub <= 单台运力最大行驶距离
                        &&
                        当前运力载重 <= 单台运力最大载重公斤)
                    {
                        当前行驶距离 += newAddedDistance2Customer;
                        当前运力载重 += newAddedWeight;
                        当前行驶路径 += "-->" + toNodeId;
                    }
                    else
                    {
                        //加当前客户距离、以及回到HUB的距离
                        当前行驶距离 += fromNode.DistanceTo(ant.DistanceHelper.hub);
                        distances.Add(当前行驶距离);
    
                        weights.Add(当前运力载重);
    
                        当前行驶路径 += "-->HUB";
                        paths.Add(当前行驶路径);
    
                        //RESET
                        当前行驶距离 = 0;
                        当前行驶距离 += ant.DistanceHelper.hub.DistanceTo(toNode);
    
                        当前运力载重 = 0;
                        当前运力载重 += toNode.需求量_公斤;
    
                        当前行驶路径 = "";
                        当前行驶路径 += "HUB-->" + toNodeId;
    
                        当前所需运力数++;
                    }
                }
    
                //回到枢纽
                当前行驶距离 += ant.DistanceHelper.customers[ant.PathNodes.Last()].DistanceTo(ant.DistanceHelper.hub);
                distances.Add(当前行驶距离);
    
                当前行驶路径 += "-->HUB";
                paths.Add(当前行驶路径);
    
    
    
                int 惩罚系数 = 0;
                if (当前所需运力数 > 拥有运力车辆数)
                    惩罚系数 = 当前所需运力数 - 拥有运力车辆数;
    
    
                ant.运输距离顺序 = distances;
                ant.运输路径 = paths;
    
                ant.Total行驶距离 = distances.Sum();
                ant.Total运力数 = 当前所需运力数;
    
                return ant.Total行驶距离 + 惩罚系数 * 惩罚权重;
            }
        }

     

    ant.DistanceHelper.hub: 是配送中心的info,有地址信息
    ant.DistanceHelper.customers: 是50个客户的info,也有地址信息
    目前为了简化,是以街道距离来计算距离的
    目前代码只是单目标优化算法,非多目标优化,后续研究研究再发文。
    上述代码其实就是第一辆车从配送中心开出到第一个客户位置,然后加上客户需求(揽的货物重量)
    接着判断能否开到下一个客户那里揽货,如果里程、重量都在限制条件只能,就开过去,不满足条件就开回枢纽;然后继续判断第二辆车,也是这么个逻辑
    最终车辆的数量就是完成这50个客户揽货所需的运力数
    万一碰到所需运力超出了限制(代码中为5辆车),这时就需要惩罚,由于最终函数返回是double,而且是越小代表越优越,因此碰到了需要惩罚的情况,实际就是大幅度的增加返回值(适应度值)
    红色部分就是惩罚变量部分。

    各种优化算法的核心写完框架后基本就不怎么变化了,最易变的其实是适应度函数的计算,如果适应度计算中用到了预测技术,还得在上面那函数里调机器学习的代码,感觉强化学习中动作施加后给出的反馈值也是这么个值

    代码下载

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-22 21:30 , Processed in 0.066466 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表