NearestSpotList SpotSearch::findNearestSpots(const Instance& tour, int tournode, unsigned int k, bool skipUsed) { unsigned spot = tour.getSpotIndex(tournode); std::vector<unsigned>* nearest = nearestSpots[spot+1]; // return a vector containing the first k entries if (k > nearest->size()) k = nearest->size(); NearestSpotList pairs; if (skipUsed) { pairs.reserve(k); for (unsigned nearestspot : *nearest) { if (tour.containsSpot(nearestspot)) continue; pairs.push_back( std::make_pair(tournode, nearestspot) ); if (pairs.size() >= k) break; } } else { pairs.resize(k); std::transform(nearest->begin(), nearest->begin() + k, pairs.begin(), [tournode](unsigned ns) { return std::make_pair(tournode, ns); } ); } return pairs; }
NearestSpotList SpotSearch::findNearestTourSpots(const Instance& tour, unsigned int k, bool uniqueSpots, bool skipUsed) { NearestSpotList nearest; nearest.reserve(k); std::vector<double> dist; dist.reserve(k); std::set<unsigned> foundSpots; // initialize with nearest spots to hotel nearest = findNearestSpots(tour, -1, k, skipUsed); for (const auto& spot : nearest) { if (uniqueSpots) foundSpots.insert(spot.second); dist.push_back(problem.getDistance(problem.getStartAsSpot(), problem.getSpot(spot.second))); } // keep track of the maximum distance of the k neighbors found so far double maxDist = dist.back(); int tourIndex = 0; for(const auto& node : tour.getTour()) { // get k nearest spots for every node in the tour, compare with current nearest spots std::vector<unsigned>* spots = nearestSpots[node.spot+1]; for (unsigned spotIndex : *spots) { if (skipUsed && tour.containsSpot(spotIndex)) continue; if (uniqueSpots && !foundSpots.insert(spotIndex).second) continue; double spotDist = problem.getDistance(problem.getSpot(node.spot), problem.getSpot(spotIndex)); // check if the list is already at size k. we can assume that if !skipUsed bool listFull = !skipUsed || dist.size() >= k; // All other spots will actually be further out, so we can stop looking // This will implicitly stop after at most k iterations, dist(spots[k]) will always be > maxDist! // (otherwise we would have added all k nearer spots to our list already) if (listFull && spotDist >= maxDist) break; // need to insert new spot into list. if (listFull) { nearest.pop_back(); dist.pop_back(); } auto distIt = std::upper_bound(dist.begin(), dist.end(), spotDist); dist.insert(distIt, spotDist); nearest.insert(nearest.begin() + (distIt - dist.begin()), std::make_pair(tourIndex, spotIndex)); maxDist = dist.back(); } tourIndex++; } return nearest; }
NearestSpot SpotSearch::findNearestSpot(const Instance& instance, int tournode, bool skipUsed) { unsigned spot = instance.getSpotIndex(tournode); std::vector<unsigned>* nearest = nearestSpots[spot+1]; for (unsigned nearestspot : *nearest) { if (skipUsed && instance.containsSpot(nearestspot)) continue; return std::make_pair(tournode,nearestspot); } // Should never be reached assert(false && "Trying to find nearest spot, but all spots are used"); return std::make_pair(tournode,-1); }
NearestNodesList SpotSearch::findNearestTourNodes(const Instance& tour, unsigned int k) { NearestNodesList nearest; nearest.reserve(k); std::vector<double> dist; dist.reserve(k); double maxDist = 0.0; int tourIndex = 0; for (const auto& node : tour.getTour()) { std::vector<unsigned>* spots = nearestSpots[node.spot+1]; for (unsigned spotIndex : *spots) { // To avoid adding duplicate entries, only add pairs where first.spot < second.spot. if (node.spot > spotIndex) continue; // skip all spots that are not on the tour if (!tour.containsSpot(spotIndex)) continue; double spotDist = problem.getDistance(problem.getSpot(node.spot), problem.getSpot(spotIndex)); if (dist.size() >= k && spotDist >= maxDist) break; // We need to get the index of the node in the tour for the nearest spot unsigned nearestnode = tour.getNodeIndex(spotIndex); if (dist.size() >= k) { nearest.pop_back(); dist.pop_back(); } auto distIt = std::upper_bound(dist.begin(), dist.end(), spotDist); dist.insert(distIt, spotDist); nearest.insert(nearest.begin() + (distIt - dist.begin()), std::make_pair(tourIndex, nearestnode)); maxDist = dist.back(); } tourIndex++; } return nearest; }