Commit e9575d03 by chamberone

feat: 提交过程打印逻辑,优化实体类,添加时间控制参数

1 parent 5022be8c
...@@ -13,11 +13,8 @@ public class DispatchConstraintProvider implements ConstraintProvider { ...@@ -13,11 +13,8 @@ public class DispatchConstraintProvider implements ConstraintProvider {
@Override @Override
public Constraint[] defineConstraints(ConstraintFactory factory) { public Constraint[] defineConstraints(ConstraintFactory factory) {
return new Constraint[] { greaterThanZero(factory), customerTimeWindowsMatch1(factory), return new Constraint[] { greaterThanZero(factory), customerTimeWindowsMatch1(factory),
customerTimeWindowsMatch2(factory), customerTimeWindowsMatch2(factory), skillMatch(factory), technicianBalance(factory),
skillMatch(factory), technicianBalance2(factory), technicianBalanceSoft(factory), totalDistance(factory),
technicianBalance(factory),
technicianBalance2(factory),
totalDistance(factory),
preferredTotalDistance(factory) }; preferredTotalDistance(factory) };
} }
...@@ -30,7 +27,7 @@ public class DispatchConstraintProvider implements ConstraintProvider { ...@@ -30,7 +27,7 @@ public class DispatchConstraintProvider implements ConstraintProvider {
// 4,技术员技能跟订单相匹配skillMatch // 4,技术员技能跟订单相匹配skillMatch
// 5,订单均分technicianBalance // 5,订单均分technicianBalance
protected Constraint greaterThanZero(ConstraintFactory factory) { public Constraint greaterThanZero(ConstraintFactory factory) {
return factory.forEach(Technician.class).filter(technician -> technician.getCustomerList().size() == 0) return factory.forEach(Technician.class).filter(technician -> technician.getCustomerList().size() == 0)
.penalizeLong(HardSoftLongScore.ONE_HARD, technician -> 1).asConstraint("每个技术员至少分配一个单子"); .penalizeLong(HardSoftLongScore.ONE_HARD, technician -> 1).asConstraint("每个技术员至少分配一个单子");
} }
...@@ -42,6 +39,7 @@ public class DispatchConstraintProvider implements ConstraintProvider { ...@@ -42,6 +39,7 @@ public class DispatchConstraintProvider implements ConstraintProvider {
} }
protected Constraint customerTimeWindowsMatch2(ConstraintFactory factory) { protected Constraint customerTimeWindowsMatch2(ConstraintFactory factory) {
// 迟到2小时惩罚
return factory.forEach(Customer.class).filter( return factory.forEach(Customer.class).filter(
customer -> customer.getTechnician() != null && customer.getArrivalTime() > customer.getEndTime() + 120) customer -> customer.getTechnician() != null && customer.getArrivalTime() > customer.getEndTime() + 120)
.penalizeLong(HardSoftLongScore.ONE_HARD, customer -> 1).asConstraint("技术员到达时间跟时间窗吻合2"); .penalizeLong(HardSoftLongScore.ONE_HARD, customer -> 1).asConstraint("技术员到达时间跟时间窗吻合2");
...@@ -51,7 +49,12 @@ public class DispatchConstraintProvider implements ConstraintProvider { ...@@ -51,7 +49,12 @@ public class DispatchConstraintProvider implements ConstraintProvider {
return factory.forEach(Customer.class) return factory.forEach(Customer.class)
.filter(customer -> customer.getTechnician() != null .filter(customer -> customer.getTechnician() != null
&& !customer.getTechnician().getSkills().contains(customer.getRequiredSkill())) && !customer.getTechnician().getSkills().contains(customer.getRequiredSkill()))
.penalizeLong(HardSoftLongScore.ONE_HARD, customer -> 1).asConstraint("技术员技能跟订单相匹配skillMatch"); .penalizeLong(HardSoftLongScore.ONE_HARD,
// 技能匹配跟时间窗匹配存在很明显的跷跷板效应,权重小于3就会存在技能匹配问题
// 3-技能匹配问题1个,时间窗问题8个
// 4-技能匹配问题0个,时间窗问题14个
customer -> 4)
.asConstraint("技术员技能跟订单相匹配skillMatch");
} }
protected Constraint technicianBalance(ConstraintFactory factory) { protected Constraint technicianBalance(ConstraintFactory factory) {
...@@ -65,9 +68,7 @@ public class DispatchConstraintProvider implements ConstraintProvider { ...@@ -65,9 +68,7 @@ public class DispatchConstraintProvider implements ConstraintProvider {
protected Constraint technicianBalance2(ConstraintFactory factory) { protected Constraint technicianBalance2(ConstraintFactory factory) {
// 单量不能过少 FIXME // 单量不能过少 FIXME
return factory.forEach(Technician.class).filter(technician -> technician.getOffWorkTime() <= 960) return factory.forEach(Technician.class).filter(technician -> technician.getOffWorkTime() <= 960)
.penalizeLong(HardSoftLongScore.ONE_HARD, .penalizeLong(HardSoftLongScore.ONE_HARD, technician -> 1).asConstraint("订单均分2");
technician -> 1)
.asConstraint("订单均分2");
} }
// protected Constraint technicianBalance(ConstraintFactory factory) { // protected Constraint technicianBalance(ConstraintFactory factory) {
...@@ -92,6 +93,7 @@ public class DispatchConstraintProvider implements ConstraintProvider { ...@@ -92,6 +93,7 @@ public class DispatchConstraintProvider implements ConstraintProvider {
// ************************************************************************ // ************************************************************************
// 1, 总路程最小 totalDistance // 1, 总路程最小 totalDistance
// 2, 技术员中心点偏好 preferredTotalDistance // 2, 技术员中心点偏好 preferredTotalDistance
// 3, 订单数量均衡 technicianBalanceSoft
protected Constraint totalDistance(ConstraintFactory factory) { protected Constraint totalDistance(ConstraintFactory factory) {
return factory.forEach(Technician.class) return factory.forEach(Technician.class)
...@@ -104,4 +106,10 @@ public class DispatchConstraintProvider implements ConstraintProvider { ...@@ -104,4 +106,10 @@ public class DispatchConstraintProvider implements ConstraintProvider {
.asConstraint("技术员中心点偏好"); .asConstraint("技术员中心点偏好");
} }
protected Constraint technicianBalanceSoft(ConstraintFactory factory) {
return factory.forEachUniquePair(Technician.class).penalizeLong(HardSoftLongScore.ONE_SOFT,
// 权重需要调节,差距一个相当于多一公里 FIXME 这里应该是时长均衡,不是订单量均衡
(a, b) -> Math.abs(a.getCustomerSize() - b.getCustomerSize()) * 1000).asConstraint("订单均分soft");
}
} }
...@@ -19,6 +19,7 @@ package com.dituhui.pea.dispatch.controller; ...@@ -19,6 +19,7 @@ package com.dituhui.pea.dispatch.controller;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.dituhui.pea.common.Result; import com.dituhui.pea.common.Result;
...@@ -35,9 +36,11 @@ public class DispatchController { ...@@ -35,9 +36,11 @@ public class DispatchController {
private DispatchService dispatchService; private DispatchService dispatchService;
@GetMapping("/manual") @GetMapping("/manual")
public Result<?> manualDispatch() { public Result<?> manualDispatch(
@RequestParam(value = "unimprovedSecondsSpentLimit", required = false) long unimprovedSecondsSpentLimit,
@RequestParam(value = "secondsSpentLimit", required = false) long secondsSpentLimit) {
try { try {
return dispatchService.manualDispatch(); return dispatchService.manualDispatch(unimprovedSecondsSpentLimit, secondsSpentLimit);
} catch (Exception e) { } catch (Exception e) {
return Result.failed(e.getMessage()); return Result.failed(e.getMessage());
} }
......
package com.dituhui.pea.dispatch.pojo; package com.dituhui.pea.dispatch.pojo;
import org.optaplanner.core.api.domain.entity.PlanningEntity; import org.optaplanner.core.api.domain.entity.PlanningEntity;
import org.optaplanner.core.api.domain.variable.InverseRelationShadowVariable;
import org.optaplanner.core.api.domain.variable.ShadowVariable; import org.optaplanner.core.api.domain.variable.ShadowVariable;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data; import lombok.Getter;
import org.optaplanner.core.api.domain.variable.InverseRelationShadowVariable; import lombok.Setter;
/** /**
* 订单 * 订单
...@@ -14,7 +15,8 @@ import org.optaplanner.core.api.domain.variable.InverseRelationShadowVariable; ...@@ -14,7 +15,8 @@ import org.optaplanner.core.api.domain.variable.InverseRelationShadowVariable;
* @author gpzhang * @author gpzhang
* *
*/ */
@Data @Setter
@Getter
@PlanningEntity @PlanningEntity
public class Customer { public class Customer {
...@@ -44,7 +46,8 @@ public class Customer { ...@@ -44,7 +46,8 @@ public class Customer {
public Customer() { public Customer() {
} }
public Customer(long id, String code, Location location, int startTime, int endTime, String requiredSkill, int serviceDuration) { public Customer(long id, String code, Location location, int startTime, int endTime, String requiredSkill,
int serviceDuration) {
this.id = id; this.id = id;
this.code = code; this.code = code;
this.location = location; this.location = location;
...@@ -145,4 +148,25 @@ public class Customer { ...@@ -145,4 +148,25 @@ public class Customer {
return previousCustomer.getLocation().getPathTimeTo(location); return previousCustomer.getLocation().getPathTimeTo(location);
} }
@Override
public int hashCode() {
return Long.valueOf(this.id).hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (!(obj instanceof Customer))
return false;
if (obj == this)
return true;
return this.id == ((Customer) obj).getId();
}
@Override
public String toString() {
return "Customer{" + "id=" + id + '}';
}
} }
...@@ -55,6 +55,21 @@ public class Location { ...@@ -55,6 +55,21 @@ public class Location {
// Complex methods // Complex methods
// ************************************************************************ // ************************************************************************
@Override
public int hashCode() {
return Long.valueOf(this.id).hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (!(obj instanceof Location))
return false;
if (obj == this)
return true;
return this.id == ((Location) obj).getId();
}
@Override @Override
public String toString() { public String toString() {
......
...@@ -13,9 +13,11 @@ import org.optaplanner.core.api.domain.variable.PlanningListVariable; ...@@ -13,9 +13,11 @@ import org.optaplanner.core.api.domain.variable.PlanningListVariable;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data; import lombok.Getter;
import lombok.Setter;
@Data @Setter
@Getter
@PlanningEntity @PlanningEntity
public class Technician { public class Technician {
...@@ -150,4 +152,27 @@ public class Technician { ...@@ -150,4 +152,27 @@ public class Technician {
} }
} }
@Override
public int hashCode() {
return Long.valueOf(this.id).hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (!(obj instanceof Technician))
return false;
if (obj == this)
return true;
return this.id == ((Technician) obj).getId();
}
@Override
public String toString() {
return "Technician{" + "id=" + id + '}';
}
} }
...@@ -26,6 +26,7 @@ import com.dituhui.pea.common.Result; ...@@ -26,6 +26,7 @@ import com.dituhui.pea.common.Result;
*/ */
public interface DispatchService { public interface DispatchService {
Result<?> manualDispatch() throws UncheckedIOException, IOException; Result<?> manualDispatch(long unimprovedSecondsSpentLimit, long secondsSpentLimit)
throws UncheckedIOException, IOException;
} }
...@@ -16,10 +16,10 @@ ...@@ -16,10 +16,10 @@
package com.dituhui.pea.dispatch.service.impl; package com.dituhui.pea.dispatch.service.impl;
import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.time.Duration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
...@@ -33,21 +33,28 @@ import java.util.stream.Collectors; ...@@ -33,21 +33,28 @@ import java.util.stream.Collectors;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RegExUtils; import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.optaplanner.core.api.score.ScoreExplanation;
import org.optaplanner.core.api.score.buildin.hardsoftlong.HardSoftLongScore;
import org.optaplanner.core.api.solver.SolutionManager;
import org.optaplanner.core.api.solver.Solver; import org.optaplanner.core.api.solver.Solver;
import org.optaplanner.core.api.solver.SolverFactory; import org.optaplanner.core.api.solver.SolverFactory;
import org.optaplanner.core.api.solver.event.BestSolutionChangedEvent;
import org.optaplanner.core.api.solver.event.SolverEventListener;
import org.optaplanner.core.config.solver.SolverConfig; import org.optaplanner.core.config.solver.SolverConfig;
import org.optaplanner.core.config.solver.termination.TerminationConfig;
import org.optaplanner.persistence.jackson.impl.domain.solution.JacksonSolutionFileIO;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.dituhui.pea.dispatch.constraint.DispatchConstraintProvider;
import com.dituhui.pea.dispatch.pojo.DispatchSolution;
import com.dituhui.pea.common.Result; import com.dituhui.pea.common.Result;
import com.dituhui.pea.dispatch.service.DispatchService; import com.dituhui.pea.dispatch.constraint.DispatchConstraintProvider;
import com.dituhui.pea.dispatch.pojo.Customer; import com.dituhui.pea.dispatch.pojo.Customer;
import com.dituhui.pea.dispatch.pojo.Depot; import com.dituhui.pea.dispatch.pojo.Depot;
import com.dituhui.pea.dispatch.pojo.DispatchSolution;
import com.dituhui.pea.dispatch.pojo.Location; import com.dituhui.pea.dispatch.pojo.Location;
import com.dituhui.pea.dispatch.pojo.Technician; import com.dituhui.pea.dispatch.pojo.Technician;
import com.dituhui.pea.dispatch.service.DispatchService;
/** /**
* @author gpzhang * @author gpzhang
...@@ -58,7 +65,7 @@ public class DispatchServiceImpl implements DispatchService { ...@@ -58,7 +65,7 @@ public class DispatchServiceImpl implements DispatchService {
private Logger logger = LoggerFactory.getLogger(getClass()); private Logger logger = LoggerFactory.getLogger(getClass());
@Override @Override
public Result<?> manualDispatch() throws UncheckedIOException, FileNotFoundException { public Result<?> manualDispatch(long unimprovedSecondsSpentLimit, long secondsSpentLimit) throws UncheckedIOException, FileNotFoundException {
logger.info("{}", "invoke manualDispatch"); logger.info("{}", "invoke manualDispatch");
// 创建解决方案对象 // 创建解决方案对象
...@@ -66,17 +73,25 @@ public class DispatchServiceImpl implements DispatchService { ...@@ -66,17 +73,25 @@ public class DispatchServiceImpl implements DispatchService {
Map<Integer, String> technicianIndexMap = loadTechnicianIndex(); Map<Integer, String> technicianIndexMap = loadTechnicianIndex();
Map<String, Set<String>> technicianCodeSkillsMap = loadTechnicianCodeSkillsMap(); Map<String, Set<String>> technicianCodeSkillsMap = loadTechnicianCodeSkillsMap();
Map<String, String> customerCodeSkillMap = loadCustomerCodeSkillMap(); Map<String, String> customerCodeSkillMap = loadCustomerCodeSkillMap();
Map<String, Map<String, Long>> preferredlocationDistanceMap =loadPreferredlocationDistanceMap(); Map<String, Map<String, Long>> preferredlocationDistanceMap = loadPreferredlocationDistanceMap();
Map<String, Integer> customerCodeServiceTimeMap = loadCustomerCodeServiceTimeMap(); Map<String, Integer> customerCodeServiceTimeMap = loadCustomerCodeServiceTimeMap();
DispatchSolution problem = createVehicleRoutingSolution(customerIndexMap, technicianIndexMap, DispatchSolution problem = createVehicleRoutingSolution(customerIndexMap, technicianIndexMap,
technicianCodeSkillsMap, customerCodeSkillMap, preferredlocationDistanceMap,customerCodeServiceTimeMap); technicianCodeSkillsMap, customerCodeSkillMap, preferredlocationDistanceMap,
customerCodeServiceTimeMap);
// 创建求解器配置 // 创建求解器配置
// 创建 SolverConfig 对象,并设置求解器配置 // 创建 SolverConfig 对象,并设置求解器配置
SolverConfig solverConfig = new SolverConfig(); SolverConfig solverConfig = new SolverConfig();
solverConfig.setSolutionClass(DispatchSolution.class); solverConfig.setSolutionClass(DispatchSolution.class);
solverConfig.withEntityClassList(Arrays.asList(Technician.class, Customer.class));// 这里不能漏掉,否则约束不生效 solverConfig.withEntityClassList(Arrays.asList(Technician.class, Customer.class));// 这里不能漏掉,否则约束不生效
solverConfig.withTerminationSpentLimit(Duration.ofSeconds(60)); TerminationConfig terminationConfig = new TerminationConfig();
// 运行时长提升效果
// 5s/60s: 技能权重4-技能匹配问题0个,时间窗问题14个
// 10s/300s: 技能权重4-技能匹配问题0个,时间窗问题9个
terminationConfig
.setUnimprovedSecondsSpentLimit(unimprovedSecondsSpentLimit == 0 ? 5 : unimprovedSecondsSpentLimit);// XX秒没有找到更好方案
terminationConfig.setSecondsSpentLimit(secondsSpentLimit == 0 ? 60 : secondsSpentLimit);// 总时间不能超过XXs
solverConfig.withTerminationConfig(terminationConfig);
// 约束条件 // 约束条件
solverConfig.withConstraintProviderClass(DispatchConstraintProvider.class); solverConfig.withConstraintProviderClass(DispatchConstraintProvider.class);
...@@ -84,21 +99,44 @@ public class DispatchServiceImpl implements DispatchService { ...@@ -84,21 +99,44 @@ public class DispatchServiceImpl implements DispatchService {
// 创建求解器 // 创建求解器
SolverFactory<DispatchSolution> solverFactory = SolverFactory.create(solverConfig); SolverFactory<DispatchSolution> solverFactory = SolverFactory.create(solverConfig);
Solver<DispatchSolution> solver = solverFactory.buildSolver(); Solver<DispatchSolution> solver = solverFactory.buildSolver();
DispatchSolution solution = solver.solve(problem); SolutionManager<DispatchSolution, HardSoftLongScore> scoreManager = SolutionManager.create(solverFactory);
solver.addEventListener(new SolverEventListener<DispatchSolution>() {
public void bestSolutionChanged(BestSolutionChangedEvent<DispatchSolution> event) {
// System.out.printf("found better score:%s at time:%ss %n", event.getNewBestScore().toShortString(),
// event.getTimeMillisSpent() / 1000);
System.out.printf("%s,%s%n", event.getNewBestScore().toLevelDoubles()[0],
event.getTimeMillisSpent() / 1000F);
}
});
DispatchSolution solution = solver.solve(problem);
printSolution(solution, customerIndexMap, technicianIndexMap); printSolution(solution, customerIndexMap, technicianIndexMap);
System.out.println("final Score: " + solution.getScore().toShortString());
System.out.println("hardScore: " + solution.getScore().hardScore());
System.out.println("softScore: " + solution.getScore().softScore()); // Create a JacksonSolutionFileIO instance.
JacksonSolutionFileIO<DispatchSolution> exporter = new JacksonSolutionFileIO<DispatchSolution>(
DispatchSolution.class);
// Set the output file.
exporter.write(solution, new File("dispatchSolution.json"));
// Obtain a ScoreExplanation object for the best solution
// Using score calculation outside the Solver
// https://www.optaplanner.org/docs/optaplanner/latest/score-calculation/score-calculation.html
ScoreExplanation<DispatchSolution, HardSoftLongScore> scoreExplanation = scoreManager.explain(solution);
System.out.println(scoreExplanation.getSummary());
// Map<String, ConstraintMatchTotal<HardSoftLongScore>> constraintMatchTotalMap = scoreExplanation
// .getConstraintMatchTotalMap();
// constraintMatchTotalMap.forEach((key, value) -> {
// System.out.println(key + ":" + value.getConstraintName() + ":" + value.getScore().toShortString());
// });
return Result.success(solution.getTechnicianList()); return Result.success(solution.getTechnicianList());
} }
private static Map<String, Integer> loadCustomerCodeServiceTimeMap() private static Map<String, Integer> loadCustomerCodeServiceTimeMap()
throws UncheckedIOException, FileNotFoundException { throws UncheckedIOException, FileNotFoundException {
List<String> customerServiceTime = IOUtils.readLines(new FileInputStream("data/customerServiceTime.csv"), "utf-8"); List<String> customerServiceTime = IOUtils.readLines(new FileInputStream("data/customerServiceTime.csv"),
"utf-8");
Map<String, Integer> customerCodeServiceTimeMap = new HashMap<String, Integer>();// code-time Map<String, Integer> customerCodeServiceTimeMap = new HashMap<String, Integer>();// code-time
for (int i = 0; i < customerServiceTime.size(); i++) { for (int i = 0; i < customerServiceTime.size(); i++) {
String line = customerServiceTime.get(i); String line = customerServiceTime.get(i);
...@@ -110,8 +148,8 @@ public class DispatchServiceImpl implements DispatchService { ...@@ -110,8 +148,8 @@ public class DispatchServiceImpl implements DispatchService {
private static Map<String, Map<String, Long>> loadPreferredlocationDistanceMap() private static Map<String, Map<String, Long>> loadPreferredlocationDistanceMap()
throws UncheckedIOException, FileNotFoundException { throws UncheckedIOException, FileNotFoundException {
List<String> technicianCodeLocation = IOUtils List<String> technicianCodeLocation = IOUtils.readLines(new FileInputStream("data/technicianLocation.csv"),
.readLines(new FileInputStream("data/technicianLocation.csv"), "utf-8"); "utf-8");
Map<String, String> technicianCodeLocationMap = new HashMap<String, String>();// 序号-code Map<String, String> technicianCodeLocationMap = new HashMap<String, String>();// 序号-code
for (int i = 0; i < technicianCodeLocation.size(); i++) { for (int i = 0; i < technicianCodeLocation.size(); i++) {
String line = technicianCodeLocation.get(i); String line = technicianCodeLocation.get(i);
...@@ -119,8 +157,8 @@ public class DispatchServiceImpl implements DispatchService { ...@@ -119,8 +157,8 @@ public class DispatchServiceImpl implements DispatchService {
technicianCodeLocationMap.put(temps[0], temps[1] + "," + temps[2]); technicianCodeLocationMap.put(temps[0], temps[1] + "," + temps[2]);
} }
List<String> customerCodeLocation = IOUtils List<String> customerCodeLocation = IOUtils.readLines(new FileInputStream("data/customerLocation.csv"),
.readLines(new FileInputStream("data/customerLocation.csv"), "utf-8"); "utf-8");
Map<String, String> customerCodeLocationMap = new HashMap<String, String>();// 序号-code Map<String, String> customerCodeLocationMap = new HashMap<String, String>();// 序号-code
for (int i = 0; i < customerCodeLocation.size(); i++) { for (int i = 0; i < customerCodeLocation.size(); i++) {
String line = customerCodeLocation.get(i); String line = customerCodeLocation.get(i);
...@@ -137,7 +175,7 @@ public class DispatchServiceImpl implements DispatchService { ...@@ -137,7 +175,7 @@ public class DispatchServiceImpl implements DispatchService {
long distance = (long) getDistance(Double.parseDouble(temps[1]), Double.parseDouble(temps[0]), long distance = (long) getDistance(Double.parseDouble(temps[1]), Double.parseDouble(temps[0]),
Double.parseDouble(temps2[1]), Double.parseDouble(temps2[0])); Double.parseDouble(temps2[1]), Double.parseDouble(temps2[0]));
Map<String, Long> customerMaps = customerTecnicianDistanceMap.get(technicianCode); Map<String, Long> customerMaps = customerTecnicianDistanceMap.get(technicianCode);
if(null == customerMaps) { if (null == customerMaps) {
customerMaps = new HashMap<String, Long>(); customerMaps = new HashMap<String, Long>();
customerTecnicianDistanceMap.put(technicianCode, customerMaps); customerTecnicianDistanceMap.put(technicianCode, customerMaps);
} }
...@@ -218,7 +256,8 @@ public class DispatchServiceImpl implements DispatchService { ...@@ -218,7 +256,8 @@ public class DispatchServiceImpl implements DispatchService {
private static DispatchSolution createVehicleRoutingSolution(Map<Integer, String> customerIndexMap, private static DispatchSolution createVehicleRoutingSolution(Map<Integer, String> customerIndexMap,
Map<Integer, String> technicianIndexMap, Map<String, Set<String>> technicianCodeSkillsMap, Map<Integer, String> technicianIndexMap, Map<String, Set<String>> technicianCodeSkillsMap,
Map<String, String> customerCodeSkillMap, Map<String, Map<String, Long>> preferredlocationDistanceMap, Map<String, Integer> customerCodeServiceTimeMap) throws UncheckedIOException, FileNotFoundException { Map<String, String> customerCodeSkillMap, Map<String, Map<String, Long>> preferredlocationDistanceMap,
Map<String, Integer> customerCodeServiceTimeMap) throws UncheckedIOException, FileNotFoundException {
DispatchSolution vehicleRoutingSolution = new DispatchSolution(); DispatchSolution vehicleRoutingSolution = new DispatchSolution();
// 翻转map // 翻转map
...@@ -351,14 +390,16 @@ public class DispatchServiceImpl implements DispatchService { ...@@ -351,14 +390,16 @@ public class DispatchServiceImpl implements DispatchService {
totalNum.addAndGet(technician.getCustomerList().size()); totalNum.addAndGet(technician.getCustomerList().size());
for (Customer customer : technician.getCustomerList()) { for (Customer customer : technician.getCustomerList()) {
Customer previousCustomer = customer.getPreviousCustomer(); Customer previousCustomer = customer.getPreviousCustomer();
int startPath, endPath;//路上时间 int startPath, endPath;// 路上时间
if (null == previousCustomer) { if (null == previousCustomer) {
startPath = technician.getDepot().getStartTime(); startPath = technician.getDepot().getStartTime();
// endPath = startPath + customer.getLocation().getPathTimeTo(technician.getDepot().getLocation()); // endPath = startPath +
// customer.getLocation().getPathTimeTo(technician.getDepot().getLocation());
endPath = startPath + technician.getDepot().getLocation().getPathTimeTo(customer.getLocation()); endPath = startPath + technician.getDepot().getLocation().getPathTimeTo(customer.getLocation());
} else { } else {
startPath = previousCustomer.getDepartureTime(); startPath = previousCustomer.getDepartureTime();
// endPath = startPath + customer.getLocation().getPathTimeTo(previousCustomer.getLocation()); // endPath = startPath +
// customer.getLocation().getPathTimeTo(previousCustomer.getLocation());
endPath = startPath + previousCustomer.getLocation().getPathTimeTo(customer.getLocation()); endPath = startPath + previousCustomer.getLocation().getPathTimeTo(customer.getLocation());
} }
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!