揽货最短路径解决方案算法 - C# 蚁群优化算法实现
需求為(自己編的,非實(shí)際項(xiàng)目):
某配送中心進(jìn)行攬貨,目標(biāo)客戶數(shù)為50個(gè)客戶,配送中心目前的運(yùn)力資源如下:
現(xiàn)有車輛5臺(tái)
單臺(tái)運(yùn)力最大行駛距離200千米
單臺(tái)運(yùn)力最大載重公斤1噸
問(wèn):運(yùn)力怎樣走法才能以最低的成本完成針對(duì)這50個(gè)客戶的攬貨行為
是個(gè)最優(yōu)化問(wèn)題(運(yùn)籌學(xué)),我們只考慮簡(jiǎn)化后的模型,不考慮路面交通、時(shí)間窗口這些復(fù)雜計(jì)算,用蟻群優(yōu)化算法來(lái)實(shí)現(xiàn)接近最優(yōu)解的計(jì)算。
關(guān)于蟻群優(yōu)化算法的理論請(qǐng)看這篇文章:https://www.cnblogs.com/asxinyu/p/Path_Optimization_Tsp_Problem_Ant_System_CSharp.html
里面的基本算法已經(jīng)寫明了,也有demo,本文是針對(duì)如何適應(yīng)到具體業(yè)務(wù)的介紹(本文用的蟻群核心代碼也是上文中改來(lái)的)
蟻群主要步驟為:
初始化(如信息素)
開始迭代
構(gòu)造各個(gè)螞蟻,以及螞蟻?zhàn)叩穆窂?#xff08;核心是針對(duì)后續(xù)節(jié)點(diǎn)的SELECT)
計(jì)算適應(yīng)度
加入優(yōu)秀螞蟻到跟蹤列表
更新信息素(根據(jù)適應(yīng)度)
結(jié)束迭代
給出報(bào)告
原文章里用的是TSP做DEMO,比較難看清楚如何應(yīng)用到實(shí)際業(yè)務(wù)邏輯中
同樣的,最困惑的核心中的核心,類似遺傳算法,也是適應(yīng)度值的計(jì)算,有的地方是一步一步增加vlaue,比如單純距離的增加,但是復(fù)雜點(diǎn)的都沒(méi)法這么操作,而是要看整體路徑的指標(biāo)(包括懲罰等)
由于蟻群優(yōu)化算法和本文代碼都能下載,所以只介紹適應(yīng)度value的計(jì)算
class FitnessValueCalculator
? ? {
? ? ? ? private static int 擁有運(yùn)力車輛數(shù) = 5;
? ? ? ? private static int 單臺(tái)運(yùn)力最大行駛距離 = 200;
? ? ? ? private static int 單臺(tái)運(yùn)力最大載重公斤 = 1000;
? ? ? ? private static double 懲罰權(quán)重 = 20;
? ? ? ? public static double Calculator(ShortestDeliverAnt ant)
? ? ? ? {
? ? ? ? ? ? var paths = new List<string>();
? ? ? ? ? ? var distances = new List<double>();
? ? ? ? ? ? var weights = new List<double>();
? ? ? ? ? ? double 當(dāng)前行駛距離 = 0;
? ? ? ? ? ? double 當(dāng)前運(yùn)力載重 = 0;
? ? ? ? ? ? string 當(dāng)前行駛路徑 = "";
? ? ? ? ? ? int 當(dāng)前所需運(yùn)力數(shù) = 1;
? ? ? ? ? ? //計(jì)算樞紐到第一個(gè)客戶配送距離
? ? ? ? ? ? 當(dāng)前行駛路徑 += "HUB-->" + ant.PathNodes.First();
? ? ? ? ? ? 當(dāng)前行駛距離 += ant.DistanceHelper.hub.DistanceTo(ant.DistanceHelper.customers[ant.PathNodes.First()]);
? ? ? ? ? ? 當(dāng)前運(yùn)力載重 += 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 (當(dāng)前行駛距離 + newAddedDistance2Customer + newAddedDistance2Hub <= 單臺(tái)運(yùn)力最大行駛距離
? ? ? ? ? ? ? ? ? ? &&
? ? ? ? ? ? ? ? ? ? 當(dāng)前運(yùn)力載重 <= 單臺(tái)運(yùn)力最大載重公斤)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? 當(dāng)前行駛距離 += newAddedDistance2Customer;
? ? ? ? ? ? ? ? ? ? 當(dāng)前運(yùn)力載重 += newAddedWeight;
? ? ? ? ? ? ? ? ? ? 當(dāng)前行駛路徑 += "-->" + toNodeId;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? else
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? //加當(dāng)前客戶距離、以及回到HUB的距離
? ? ? ? ? ? ? ? ? ? 當(dāng)前行駛距離 += fromNode.DistanceTo(ant.DistanceHelper.hub);
? ? ? ? ? ? ? ? ? ? distances.Add(當(dāng)前行駛距離);
? ? ? ? ? ? ? ? ? ? weights.Add(當(dāng)前運(yùn)力載重);
? ? ? ? ? ? ? ? ? ? 當(dāng)前行駛路徑 += "-->HUB";
? ? ? ? ? ? ? ? ? ? paths.Add(當(dāng)前行駛路徑);
? ? ? ? ? ? ? ? ? ? //RESET
? ? ? ? ? ? ? ? ? ? 當(dāng)前行駛距離 = 0;
? ? ? ? ? ? ? ? ? ? 當(dāng)前行駛距離 += ant.DistanceHelper.hub.DistanceTo(toNode);
? ? ? ? ? ? ? ? ? ? 當(dāng)前運(yùn)力載重 = 0;
? ? ? ? ? ? ? ? ? ? 當(dāng)前運(yùn)力載重 += toNode.需求量_公斤;
? ? ? ? ? ? ? ? ? ? 當(dāng)前行駛路徑 = "";
? ? ? ? ? ? ? ? ? ? 當(dāng)前行駛路徑 += "HUB-->" + toNodeId;
? ? ? ? ? ? ? ? ? ? 當(dāng)前所需運(yùn)力數(shù)++;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? //回到樞紐
? ? ? ? ? ? 當(dāng)前行駛距離 += ant.DistanceHelper.customers[ant.PathNodes.Last()].DistanceTo(ant.DistanceHelper.hub);
? ? ? ? ? ? distances.Add(當(dāng)前行駛距離);
? ? ? ? ? ? 當(dāng)前行駛路徑 += "-->HUB";
? ? ? ? ? ? paths.Add(當(dāng)前行駛路徑);
? ? ? ? ? ? int 懲罰系數(shù) = 0;
? ? ? ? ? ? if (當(dāng)前所需運(yùn)力數(shù) > 擁有運(yùn)力車輛數(shù))
? ? ? ? ? ? ? ? 懲罰系數(shù) = 當(dāng)前所需運(yùn)力數(shù) - 擁有運(yùn)力車輛數(shù);
? ? ? ? ? ? ant.運(yùn)輸距離順序 = distances;
? ? ? ? ? ? ant.運(yùn)輸路徑 = paths;
? ? ? ? ? ? ant.Total行駛距離 = distances.Sum();
? ? ? ? ? ? ant.Total運(yùn)力數(shù) = 當(dāng)前所需運(yùn)力數(shù);
? ? ? ? ? ? return ant.Total行駛距離 + 懲罰系數(shù) * 懲罰權(quán)重;
? ? ? ? }
? ? }
ant.DistanceHelper.hub: 是配送中心的info,有地址信息ant.DistanceHelper.customers: 是50個(gè)客戶的info,也有地址信息
目前為了簡(jiǎn)化,是以街道距離來(lái)計(jì)算距離的目前代碼只是單目標(biāo)優(yōu)化算法,非多目標(biāo)優(yōu)化,后續(xù)研究研究再發(fā)文。
上述代碼其實(shí)就是第一輛車從配送中心開出到第一個(gè)客戶位置,然后加上客戶需求(攬的貨物重量)
接著判斷能否開到下一個(gè)客戶那里攬貨,如果里程、重量都在限制條件只能,就開過(guò)去,不滿足條件就開回樞紐;然后繼續(xù)判斷第二輛車,也是這么個(gè)邏輯
最終車輛的數(shù)量就是完成這50個(gè)客戶攬貨所需的運(yùn)力數(shù)
萬(wàn)一碰到所需運(yùn)力超出了限制(代碼中為5輛車),這時(shí)就需要懲罰,由于最終函數(shù)返回是double,而且是越小代表越優(yōu)越,因此碰到了需要懲罰的情況,實(shí)際就是大幅度的增加返回值(適應(yīng)度值)
紅色部分就是懲罰變量部分。
各種優(yōu)化算法的核心寫完框架后基本就不怎么變化了,最易變的其實(shí)是適應(yīng)度函數(shù)的計(jì)算,如果適應(yīng)度計(jì)算中用到了預(yù)測(cè)技術(shù),還得在上面那函數(shù)里調(diào)機(jī)器學(xué)習(xí)的代碼,感覺強(qiáng)化學(xué)習(xí)中動(dòng)作施加后給出的反饋值也是這么個(gè)值
原文:https://www.cnblogs.com/aarond/p/ant_wuliu.html
.NET社區(qū)新聞,深度好文,歡迎訪問(wèn)公眾號(hào)文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的揽货最短路径解决方案算法 - C# 蚁群优化算法实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: .NET Core UI框架Avalon
- 下一篇: C#热度不如Java?网友呛声:还有使用