0

我正在使用 JSprit 解决具有时间窗的多旅行推销员问题:我有一个推销员必须在一周内尽可能快地访问 n 个客户,但时间有限。我为每一天配置了一辆车,为每个客户配置了一项服务。

它实际上正在工作,但我找不到处理在特定时间计划的工作的方法。例如,一位推销员有 15 个客户要见,但在星期一下午 3 点,他安排了一个约会。考虑到该约束,我希望优化路线。

我试图指定一个时间窗口与约会相对应的工作,但通常没有分配工作,而仍有车辆可用!我试图将所需的技能放在工作和与正确日期相关的车辆上,并获得相同的结果。

所以这是我的问题: - 我不能在特定时间将工作设置为强制性(不能不分配)。- 我不明白为什么有未使用的车辆而有未分配的工作。

编辑:我修改我的代码以添加优先级并扩大时间窗口作为建议。不走运,作业 1 仍未分配。

public class test {


private ArrayList<Service> serviceList; // list of services
private ArrayList<Location> locationList; // list of location
private Location dep;   // departure & arrival for each day
private String parameters;
// distances between locations
private double times[][]; 



public test()
{
    this.serviceList = new ArrayList<>();
    this.locationList = new ArrayList<>();
    this.parameters = "";

}

public void test(int nb)
{
   this.times = new double[nb+1][nb+1];

   // collect data from json for the list of geocoded services

     try (InputStream in = new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8));
     JsonReader read = javax.json.Json.createReader(in)) {

        JsonObject obj = read.readObject();
        JsonArray results = obj.getJsonArray("clients");

        // departure
        dep = Location.Builder.newInstance().setId("0").setIndex(0).setCoordinate(Coordinate.newInstance(48.88626, 2.22135)).build();
        // parameters for OSRM request
        parameters = "&loc=48.88626, 2.22135";

        locationList.add(dep);

        // get locations from json
       for(int i=0; i<nb;i++)
       {
           JsonObject result = results.getValuesAs(JsonObject.class).get(i);
           Location l = Location.Builder.newInstance().setId(Integer.toString(i+1)).setIndex(i+1).setCoordinate(Coordinate.newInstance(Double.valueOf(result.getString("latitude")), Double.valueOf(result.getString("longitude")))).build();
           locationList.add(l);
           // parameters for OSRM request
           parameters += "&loc="+result.getString("latitude")+","+result.getString("longitude");
       }

    // Vehicles     
    VehicleTypeImpl.Builder vehicleTypeBuilder = VehicleTypeImpl.Builder.newInstance("vehicleType");
    VehicleType vehicleType = vehicleTypeBuilder.setCostPerTransportTime(1).setCostPerWaitingTime(1).setCostPerServiceTime(1).setCostPerDistance(0).build();

    // vehicule for each day
    VehicleImpl vehicleMon = VehicleImpl.Builder.newInstance("vehicleMon").setType(vehicleType).setStartLocation(dep).setEarliestStart(32400).setLatestArrival(64800).build();
    VehicleImpl vehicleTue = VehicleImpl.Builder.newInstance("vehicleTue").setType(vehicleType).setStartLocation(dep).setEarliestStart(118800).setLatestArrival(151200).build();
    VehicleImpl vehicleWed = VehicleImpl.Builder.newInstance("vehicleWed").setType(vehicleType).setStartLocation(dep).setEarliestStart(205200).setLatestArrival(237600).build();
    VehicleImpl vehicleThu = VehicleImpl.Builder.newInstance("vehicleThu").setType(vehicleType).setStartLocation(dep).setEarliestStart(291600).setLatestArrival(324000).build();
    VehicleImpl vehicleFry = VehicleImpl.Builder.newInstance("vehicleFry").setType(vehicleType).setStartLocation(dep).setEarliestStart(378000).setLatestArrival(410400).build();
    VehicleImpl vehicleSat = VehicleImpl.Builder.newInstance("vehicleSat").setType(vehicleType).setStartLocation(dep).setEarliestStart(464400).setLatestArrival(496800).build();
    VehicleImpl vehicleSun = VehicleImpl.Builder.newInstance("vehicleSun").setType(vehicleType).setStartLocation(dep).setEarliestStart(550800).setLatestArrival(583200).build();


    // the job with a specific time window which represent a scheduled appointment 
    Service serviceTW = Service.Builder.newInstance(Integer.toString(1))
                .setName("1")
                .addTimeWindow(124200, 131400) // 2 hours window
                .setPriority(1) // high priority 
                .setServiceTime(3600).setLocation(locationList.get(1)).build(); 

        serviceList.add(serviceTW);

    // jobs
    for(int i=1; i<nb; i++) // we skip the first one which is above
    {
        Service service = Service.Builder.newInstance(Integer.toString(i+1))
                .setName(Integer.toString(i+1))
                .setPriority(3) // low priority
                .addTimeWindow(32400, 583200) // time window for all week
                .setServiceTime(3600).setLocation(locationList.get(i+1)).build();
        serviceList.add(service);
    }

    // matrix time
        // retrieve traveling time from OSRM
    getOSRM_times();

    VehicleRoutingTransportCostsMatrix.Builder costMatrixBuilder = VehicleRoutingTransportCostsMatrix.Builder.newInstance(true);

    for(int i=0; i<nb ;i++)
    {
        for(int j=0; j<nb+1;j++)
        {
            costMatrixBuilder.addTransportTime(Integer.toString(i), Integer.toString(j), times[i][j]/10);
        }

    }
    // adding vehicles
    VehicleRoutingTransportCosts costMatrix = costMatrixBuilder.build();
    VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
    vrpBuilder
            .addVehicle(vehicleMon)
            .addVehicle(vehicleTue)
            .addVehicle(vehicleWed)
            .addVehicle(vehicleThu)
            .addVehicle(vehicleFry)
            .addVehicle(vehicleSat)
            .addVehicle(vehicleSun)
            .addAllJobs(serviceList).setFleetSize(FleetSize.FINITE).setRoutingCost(costMatrix);


// Problem/Solution
VehicleRoutingProblem problem = vrpBuilder.build();
VehicleRoutingAlgorithm algorithm = Jsprit.createAlgorithm(problem);
Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions();
VehicleRoutingProblemSolution bestSolution = Solutions.bestOf(solutions);

File dir = new File("output");
    // if the directory does not exist, create it
    if (!dir.exists()){
        System.out.println("creating directory ./output");
        boolean result = dir.mkdir();  
        if(result) System.out.println("./output created");  
    }


    // RESULTS
        //xml
    new VrpXMLWriter(problem, solutions).write("output/problem-with-solution.xml");
        // console
   SolutionPrinter.print(problem, bestSolution, Print.VERBOSE);
        // image
   new Plotter(problem,bestSolution).setLabel(Plotter.Label.ID).plot("output/solution.png", "solution");

   }catch (IOException ex) {Logger.getLogger(Json.class.getName()).log(Level.SEVERE, null, ex);}

}

我注意到,如果我改变了我固定工作的日期,分配给这一天的车辆将永远是满的,而工作是未分配的。

4

1 回答 1

1

实际上,我认为您对可能导致问题的服务时间窗口的定义过于复杂。当没有可用车辆时,Jsprit 无法分配服务。所以,我会继续每天定义你的车辆,就像你一样,但我会用.addTimeWindow(32400, 583200). 每个只能维修一次,并且只能在车辆可用时进行维修,因此它可以满足您正在寻找的目的,而无需花费大量时间来处理时间窗口。

如果固定的承诺比一周中任何时候都可以处理的事情更重要,那么现在是测试工作优先级的新功能的好时机:)

于 2016-05-30T16:35:23.017 回答