【发布时间】:2020-08-13 09:57:18
【问题描述】:
我正在基于 Google 的 ORTools 构建车辆路径问题的求解器。
对于简单的问题或高容量问题,它可以正常工作,但对于大多数“真实”数据集,我最终得到的解决方案要么无限期运行,要么超时。
经过一番思考,我意识到并非所有现实世界的问题都可以解决或优化。例如。我可能希望大多数车辆每天行驶不超过 500 公里。但是,如果我必须向 600 公里外的人送货,整个解决方案都会失败。
我该如何处理这些情况?现在它似乎是一个二进制通过或失败。对于某些情况被忽略或返回次优解决方案,我感到非常高兴。
这是我的解决方案的代码
public List<OptimisedVehicleRoute> Start(Location depot, List<Location> locations, int numVehicles = 1, float maxDistanceKmPerVehicle = 1000f, float maxDistanceKmSlack = 5f)
{
// Create Routing Index Manager
var depotIndex = locations.IndexOf(depot);
var manager = new RoutingIndexManager(locations.Count, numVehicles, depotIndex);
Console.WriteLine($"Depot at {depot.Postcode}");
var routing = new RoutingModel(manager);
var numCalls = 0l;
int transitCallbackIndex = routing.RegisterTransitCallback((long fromIndex, long toIndex) =>
{
numCalls++;
// Convert from routing variable Index to distance matrix NodeIndex.
var fromNode = manager.IndexToNode(fromIndex);
var toNode = manager.IndexToNode(toIndex);
var fromLocation = locations[fromNode];
var toLocation = locations[toNode];
var mDistance = fromLocation.DistanceTo(toLocation);
return mDistance;
});
// The arc cost evaluator tells the solver how to calculate the cost of travel between any two locations
routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
long maxVehicleDistanceSlack = (long)Math.Round(maxDistanceKmSlack * 1000); // slack per day
long maxVehicleDistance = (long)Math.Round(maxDistanceKmPerVehicle * 1000); // 1000km max distance per day
routing.AddDimension(transitCallbackIndex, maxVehicleDistanceSlack, maxVehicleDistance, true, "Distance");
RoutingDimension distanceDimension = routing.GetMutableDimension("Distance");
distanceDimension.SetGlobalSpanCostCoefficient(100);
var searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters();
searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc;
var timer = new Stopwatch();
timer.Start();
searchParameters.LogSearch = true;
var solution = routing.SolveWithParameters(searchParameters);
timer.Stop();
Console.WriteLine(timer.Elapsed.TotalSeconds);
var optimisedVehicleRoutes = this.CreateOptimisedVehicleLocations(locations, numVehicles, routing, manager, solution);
this.OptimisedDistanceKm = optimisedVehicleRoutes.Sum(r => r.TotalDistanceKm);
routing.Dispose();
return optimisedVehicleRoutes;
}
附:如果有人可以帮助我了解“Slack”的实际用途,我将不胜感激。我最初假设它是每辆车的容差(即 10 公里的松弛允许该车辆在其最大路线距离上行驶 10 公里)。但现在我不确定
【问题讨论】:
-
Slack 是为司机准备的,因此司机不会违反交通规则,司机的工作时间不会超过允许的时间或考虑天气条件。
-
谢谢!那么你将如何使用它呢?我想那么我在这里错误地使用了 Slack?你如何解释公差?
-
这种情况下的公差是多少?公差是为了确保司机在不违反任何规则或规定的情况下到达目的地。
-
Slack 是指货物可能需要多长时间/多短的时间,这些因素包括:天气、卡车抛锚、上一站装载/卸载需要很长时间。
-
通常模型有两个维度,一个是距离,一个是时间。沿着路径,每个节点都与一个累积变量相关联。公式为
cumul(next(I)) = cumul(I) + transit(I, next(I)) + slack(I)。对于距离,slack 很可能总是 0。对于时间,它可以不为零,然后它对应于节点之前的等待时间。