1. Incorporating Time Windows
To include time windows for each customer, we need to define the additional parameters:
- \(e_i\): Earliest start time for serving customer at node \(i\).
- \(l_i\): Latest start time for serving customer at node \(i\).
Then, we can add a time window constraint to esure each customer is served within their specific time frame:
\[
e_i \leq s_{ik} \leq l_i \quad \forall i \in \mathcal{C}, \forall k \in \mathcal{V}
\]
And update the time constraint:
\[
s_{ik} + t_{ij} - s_{jk} \leq M(1 - x_{ijk}) \quad \forall i, j \in \mathcal{N}, \forall k \in \mathcal{V}
\]
Where \(M\) is a large constant.
2. Limiting the Fleet Size
To limit the fleet size, we add a new constraint on the maximum number of vehicles used \(K_{\text{max}}\):
\[
\sum_{k \in \mathcal{V}} y_k \leq K_{\text{max}}
\]
Where \(y_k\) is a binary variable indicating if vehicle \(k\) is used. To connect the use of a vehicle \(k\) (\(y_k\)) to its routing decisions (\(x_{ijk}\)), we consider that if a vehicle is used (\(y_k = 1\)), it must leave from and return to the depot. If a vehicle is not used (\(y_k = 0\)), it cannot leave from or return to the depot.
\[
\sum_{j \in \mathcal{N}} x_{0jk} = y_k \quad \forall k \in \mathcal{V}
\]
\[
\sum_{i \in \mathcal{N}} x_{i,n+1,k} = y_k \quad \forall k \in \mathcal{V}
\]
In this model, we consider that each vehicle can only have at most one trip assigned to it, starting and ending at the depot. In some VRP settings, vehicles can be required to do many trips back and forth from the depot (see the multi-trip VRP by Brandao and Mercer 1998).
3. Minimizing Waiting Times
To minimize waiting times, we can adjust the objective function to include a penalty for waiting \(w_{ik}\) (waiting at node \(i\) for vehicle \(k\)).
Then, we can add a term to the objective function to minimize waiting times, weighted by a penalty factor \(\alpha\):
\[
\min \sum_{k \in \mathcal{V}} \sum_{i \in \mathcal{N}} \sum_{j \in \mathcal{N}} c_{ij}x_{ijk} + \alpha \sum_{k \in \mathcal{V}} \sum_{i \in \mathcal{C}} w_{ik}
\]
Waiting times are calculated using a constraint as the difference between arrival times and earliest start times:
\[
w_{ik} \geq e_i - s_{ik} \quad \forall i \in \mathcal{C}, \forall k \in \mathcal{V}
\]
Validation:
Considering the following problem input:
- Nodes: [np.int64(0), np.int64(1), np.int64(2), np.int64(3), np.int64(4), np.int64(5)]
- Customers: [np.int64(1), np.int64(2), np.int64(3), np.int64(4)]
- Demands: [0, 1, 2, 3, 4, 0]
- Earliest arrival times: [0, 0, 0, 0, 0, 0]
- Latest arrival times: [999999, 100, 100, 100, 100, 999999]
- Vehicles: [np.int64(1), np.int64(2), np.int64(3)]
- Weight for waiting times \(\alpha\): 0.5
And assuming 10-unit travel times, as shown in Table 6.1:
We have the following results:
s_1_1 = 10.0
s_2_3 = 10.0
s_3_3 = 20.0
s_4_1 = 20.0
s_5_1 = 30.0
s_5_3 = 30.0
w_1_1 = 10.0
w_2_3 = 10.0
w_3_3 = 20.0
w_4_1 = 20.0
w_5_1 = 30.0
w_5_3 = 30.0
x_0_1_1 = 1.0
x_0_2_3 = 1.0
x_1_4_1 = 1.0
x_2_3_3 = 1.0
x_3_5_3 = 1.0
x_4_5_1 = 1.0
y_1 = 1.0
y_3 = 1.0
Total cost = 120.0
- Route:
[0, np.int64(1), np.int64(4), np.int64(5)]
- Arrivals:
[0.0, 10.0, 20.0, 30.0]
- Waitings:
[0.0, 10.0, 20.0, 30.0]
- Route:
[0, np.int64(2), np.int64(3), np.int64(5)]
- Arrivals:
[0.0, 10.0, 20.0, 30.0]
- Waitings:
[0.0, 10.0, 20.0, 30.0]