【发布时间】:2021-12-05 09:42:18
【问题描述】:
跟随python示例here
我正在尝试在 java 中构建相同的功能 - 加载东西并交付给客户,如果下一个需求超过剩余容量,那么去仓库并重新加载。所有这一切都在没有任何时间限制的情况下发生,但是在我的情况下只有一辆车。问题是解决方案在很多情况下都是空的。
例如:需求:[0, -30, -30, -30, 17, 17, 18, 18, 18, 18] 车辆容量为 30 的结果为 null。但是,不同车辆容量的相同需求可以正常工作,例如-18、36、48、96。
第一个要求是 0,因为这是起始位置。
这是我正在使用的代码:
final OrDataModel data = buildDataModel();
RoutingIndexManager manager = new RoutingIndexManager(data.distanceMatrix.length, data.vehicleNumber, data.depot);
RoutingModel routing = new RoutingModel(manager);
final int transitCallbackIndex =
routing.registerTransitCallback((long fromIndex, long toIndex) -> {
int fromNode = manager.indexToNode(fromIndex);
int toNode = manager.indexToNode(toIndex);
return data.distanceMatrix[fromNode][toNode];
});
routing.setArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
routing.addDimension(transitCallbackIndex, 0, 1000000, true, "Distance");
RoutingDimension distanceDimension = routing.getDimensionOrDie("Distance");
distanceDimension.setGlobalSpanCostCoefficient(100);
final int demandCallbackIndex = routing.registerUnaryTransitCallback(
(long fromIndex) -> {
// Convert from routing variable Index to user NodeIndex.
int fromNode = manager.indexToNode(fromIndex);
return data.demands[fromNode];
});
routing.addDimension(demandCallbackIndex, data.vehicleCapacity, data.vehicleCapacity, true, "Capacity");
RoutingDimension capacityDimension = routing.getDimensionOrDie("Capacity");
//No penalty in case multi-trip visit is skipped when not required
for(int i = 1; i <= data.multiTrips - 1; i++) {
int fromNode = manager.indexToNode(i);
routing.addDisjunction(new long[] { fromNode }, 0);
}
// Setting first solution heuristic.
RoutingSearchParameters searchParameters =
main.defaultRoutingSearchParameters()
.toBuilder()
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
.setLocalSearchMetaheuristic(LocalSearchMetaheuristic.Value.GUIDED_LOCAL_SEARCH)
.setTimeLimit(Duration.newBuilder().setSeconds(1).build())
.build();
// Solve the problem.
Assignment solution = routing.solveWithParameters(searchParameters);
if(solution != null) {
printSolution(data, routing, manager, solution);
} else {
System.out.print("no results");
}
private static OrDataModel buildDataModel() {
List<Long> volumes = new ArrayList<>();
List<double[]> locations = new ArrayList<>();
readCsvFile(volumes, locations);
double totalVolume = LCollectionUtils.sumDoubleProperty(volumes, volume -> volume);
int maxCapacity = 30;
int multiTrips = calculateMultiTrips(totalVolume, maxCapacity);
List<double[]> multiTripLocations = new ArrayList<>();
for(int i = 0; i < multiTrips; i++) {
multiTripLocations.add(new double[] { 24.3653, 54.7136 });
}
List<double[]> allLocations = new ArrayList<double[]>(multiTripLocations);
allLocations.addAll(locations);
double[][] matrix = new double[allLocations.size()][];
matrix = allLocations.toArray(matrix);
long[][] distanceMatrix = buildDistanceMatrix(matrix, multiTrips);
long[][] timeMatrix = buildTimeMatrix(matrix, multiTrips);
long[] demands = fillDemands(multiTrips, matrix.length, volumes, maxCapacity);
long[][] timeWindows = fillTimeWindow(allLocations.size(), multiTrips);
return OrDataModel.from(matrix, distanceMatrix, timeMatrix, demands, allLocations.size(), multiTrips, maxCapacity, timeWindows, totalVolume);
}
private static long[] fillDemands(int minimumMultiTrips, int numberOfLocations, List<Long> allVolumes, long vehicleCapacity) {
long[] demands = new long[numberOfLocations];
//first demand is at depot so 0
demands[0] = 0;
int index;
for(index = 1; index < minimumMultiTrips; index++) {
demands[index] = (long)-vehicleCapacity;
}
for(int j = 0; j < allVolumes.size(); j++) {
demands[index] = allVolumes.get(j);
index++;
}
return demands;
}
private static int calculateMultiTrips(double totalVolume, int capacity) {
double remainder = totalVolume % capacity;
double quotient = totalVolume / capacity;
double multiTrip = remainder == 0 ? quotient : quotient + 1;
return (int)multiTrip;
}
private static long[][] buildDistanceMatrix(double[][] locations, int minimumMultiTrips) {
long[][] distanceData = new long[locations.length][locations.length];
for (int i = 0; i < locations.length; i++) {
LatLng fromLatLng = new LatLng().lat(locations[i][0]).lng(locations[i][1]);
for (int j = 0; j < locations.length; j++) {
if (i == j) {
distanceData[i][j] = 0;
}
else if(i < minimumMultiTrips && j < minimumMultiTrips) {
distanceData[i][j] = 100000;
}
else {
LatLng toLatLng = new LatLng().lat(locations[j][0]).lng(locations[j][1]);
LatLngQueryDataFetcher distanceFetcher = new HaversineDistanceFetcher(30, 1.25);
sh.locus.pjp.server.model.distance.TimeDistancePair response = distanceFetcher.fetch(fromLatLng, toLatLng);
distanceData[i][j] = response.getDistance();
}
}
}
return distanceData;
}
代码很简单。从 csv 文件读取需求,经纬度。硬编码此示例的 homebase 位置。构建距离和时间矩阵,但仅使用距离矩阵。我可能错过了什么?
【问题讨论】: