我的问题是CVRP的修改,最终也将包括时间窗口。由于时间窗口已经嵌入到示例中,因此我不应该太难理解它们。但是,我需要更改CVRP示例的核心约束之一,并且我对如何执行此操作感到有点迷失。
在我尝试建模的系统中,车辆可以离开其仓库,转到几个不同的客户,并加载材料。但是,我的模型与示例的不同之处在于,车辆可以访问任何Depot中链以存入其当前负载。
我一直在查看文档,试图弄清楚如何做到这一点,到目前为止我的基本理解是我必须更改Depot的定义(可能通过实现Standstill)能够成为车辆访问的一系列地方的一部分,和/或可能只是将Depot整合到客户中,并采用某种特殊规则,即访问车站会清空车辆而不是增加需求。我也一直在关注影子变量和可变听众,但我不知道这是否是正确的方法。这有点令人困惑。
任何人都可以提供一些提示或建议,或者在我将自己挖到一个洞之前指出我在哪里开始的正确方向?
答案 0 :(得分:0)
根据杰弗里(Geoffrey)的建议,将您的Vehicle
类重命名为VehicleTrip
,并为其赋予一个值previousVehicleTrip
,使其指向上一个和下一个旅行。和nextVehicleTrip
,并为其提供可变的开始时间和结束时间(Kotlin中的代码示例):
class VehicleTrip(
...,
var startTime: LocalDateTime? = null,
var endTime: LocalDateTime? = null,
val previousVehicleTrip?: VehicleTrip = null,
val nextVehicleTrip?: VehicleTrip = null
) : Standstill {
...
}
您可以在启动VehicleTrips
时设置这些值。当您基于StackOverFlowError
获得VehicleTrip.hashCode()
时,只需覆盖hashCode()
类的VehicleTrip
函数。 (也许有人对此有更好的建议?)
在Customer
类中,应该有一个变量arrivalTime
(类似于CVRPTW示例),它是一个自定义阴影变量。在此变量的侦听器类中,通常只更新车辆在客户处的到达时间,以及在此行程中接下来到达的客户的到达时间。现在,您还需要更新当前客户出差之后的所有出差时间。
例如,您可能有两次旅行VT1
和VT2
,并且有三个客户C1
,C2
和C3
。从
VT1 - C1 - VT2 - C2 - C3
到
VT1 - C2 - C1 - VT2 - C3
您想要更新的东西是(按顺序)
C2.arrivalTime
C1.arrivalTime
VT1.endTime
VT2.startTime
C3.arrivalTime
VT2.endTime
请注意,在TimeWindowedCustomer
示例中,变量侦听器仅执行步骤1和2.。因此,我们必须添加步骤3至6。
为此,请在@CustomShadowVariable
的开始和结束时间添加VehicleTrip
批注(并且不要忘记将VehicleTrip
标记为计划实体),该注释使用与时间窗口客户相同的变量侦听器类:
class VehicleTrip(
...,
@CustomShadowVariable(
variableListenerRef = PlanningVariableReference(
entityClass = TimeWindowedCustomer::class,
variableName = "arrivalTime"
))
var startTime: LocalDateTime? = null,
...
) : Standstill {
...
}
现在在ArrivalTimeUpdatingVariableListener
类中,您可以添加步骤3.到6.,类似于步骤1.和2.的实现方式。确保保留更新这些变量的顺序,并在使用ScoreDirector
和beforeVariableChanged()
方法更改变量时通知afterVariableChanged()
。