| 164 | } |
| 165 | |
| 166 | Solution::Solution(ProblemData const &data, RandomNumberGenerator &rng) |
| 167 | : neighbours_(data.numLocations(), std::nullopt) |
| 168 | { |
| 169 | // Add all required and randomly selected optional clients. |
| 170 | std::vector<size_t> clients; |
| 171 | clients.reserve(data.numClients()); |
| 172 | for (size_t idx = data.numDepots(); idx != data.numLocations(); ++idx) |
| 173 | { |
| 174 | ProblemData::Client const &clientData = data.location(idx); |
| 175 | if (clientData.required || rng.rand() < 0.5) |
| 176 | clients.push_back(idx); |
| 177 | } |
| 178 | |
| 179 | // Shuffle clients to create random routes. |
| 180 | rng.shuffle(clients.begin(), clients.end()); |
| 181 | |
| 182 | // Distribute clients evenly over the routes: the total number of |
| 183 | // clients per vehicle, with an adjustment in case the division is not |
| 184 | // perfect and there are not enough vehicles for single-client routes. |
| 185 | auto const numVehicles = data.numVehicles(); |
| 186 | auto const numClients = clients.size(); |
| 187 | auto const perVehicle = std::max<size_t>(numClients / numVehicles, 1); |
| 188 | auto const adjustment |
| 189 | = numClients > numVehicles && numClients % numVehicles != 0; |
| 190 | auto const perRoute = perVehicle + adjustment; |
| 191 | auto const numRoutes = (numClients + perRoute - 1) / perRoute; |
| 192 | |
| 193 | std::vector<std::vector<Client>> routes(numRoutes); |
| 194 | for (size_t idx = 0; idx != numClients; ++idx) |
| 195 | routes[idx / perRoute].push_back(clients[idx]); |
| 196 | |
| 197 | std::vector<size_t> vehTypes; |
| 198 | vehTypes.reserve(data.numVehicles()); |
| 199 | for (size_t vehType = 0; vehType != data.numVehicleTypes(); ++vehType) |
| 200 | { |
| 201 | auto const numAvailable = data.vehicleType(vehType).numAvailable; |
| 202 | std::fill_n(std::back_inserter(vehTypes), numAvailable, vehType); |
| 203 | } |
| 204 | |
| 205 | if (data.numVehicleTypes() > 1) |
| 206 | // Shuffle vehicle types when there is more than one. This ensures |
| 207 | // some additional diversity in the initial solutions, which |
| 208 | // sometimes (e.g. with heterogeneous fleet VRP) matters for |
| 209 | // consistent convergence. |
| 210 | rng.shuffle(vehTypes.begin(), vehTypes.end()); |
| 211 | |
| 212 | routes_.reserve(numRoutes); |
| 213 | for (size_t idx = 0; idx != routes.size(); idx++) |
| 214 | routes_.emplace_back(data, routes[idx], vehTypes[idx]); |
| 215 | |
| 216 | *this = Solution(data, routes_); |
| 217 | } |
| 218 | |
| 219 | Solution::Solution(ProblemData const &data, |
| 220 | std::vector<std::vector<Client>> const &routes) |