src/drop.cpp
/**
 * This is similar to the exchange_heuristic but drops k consecutive markets
 * from the tour and tries to insert a single one from the unvisited.
 */
This is similar to the exchange_heuristic but drops k consecutive markets
from the tour and tries to insert a single one from the unvisited.
This is similar to the exchange_heuristic but drops k consecutive markets from the tour and tries to insert a single one from the unvisited .
int k_exchange_heuristic(const TPP::Instance &instance, TPP::Solution &sol,
                         const uint32_t k) {
    LOG_SCOPE_F(INFO, "k_exchange_heuristic");
    LOG_F(INFO, "Start cost: %d", sol.cost_);
    auto total_cost_change = 0;
    auto unselected = sol.get_unselected_markets();
    auto solution_changed = false;
    const auto route_copy = sol.route_;
    struct MarketPosition {
        size_t market_{ 0 };
        size_t position_{ 0 };
        bool operator<(const MarketPosition &rhs) {
            return this->position_ < rhs.position_;;
        }
    };
    vector<MarketPosition> rem_markets;
    rem_markets.reserve(k);
    for (auto i = 1u; i + k - 1 < route_copy.size(); ++i) {
        const auto cost_before_removal = sol.cost_;
        rem_markets.clear();
        for (auto j = 0u; j < k; ++j) {
            const auto market = route_copy.at(i + j);
            const auto pos = sol.get_market_pos_in_route(market);
            rem_markets.push_back(MarketPosition{ market, pos });
        }
        sort(begin(rem_markets), end(rem_markets));
        for (auto it = rem_markets.rbegin(); it != rem_markets.rend(); ++it) {
            const auto &el = *it;
            sol.remove_market_at_pos(el.position_);
        }
        bool found = false;
        for (auto cand : unselected) {
            if ( !sol.check_market_satisfies_demand(cand) ) {
                continue ;
            }
            const auto verdict = sol.calc_market_add_cost(cand);
            if (sol.cost_ + verdict.cost_change_ < cost_before_removal
                    && verdict.demand_satisfied_) {
                LOG_F(INFO, "Cost of adding %zu is %d at pos %zu",
                        cand, verdict.cost_change_, verdict.index_);
                const auto prev_cost = sol.cost_;
                total_cost_change += verdict.cost_change_;
                sol.insert_market_at_pos(cand, verdict.index_);
                CHECK_F(prev_cost + verdict.cost_change_ == sol.cost_,
                        "Updated cost should be OK, %d", sol.cost_);
                LOG_F(INFO, "Cost now: %d", sol.cost_);
                unselected.erase(find(begin(unselected), end(unselected), cand));
                found = true;
                break ;
            }
        }
        if (found) {
            solution_changed = true;
            i += k - 1; 
        } else { 
            for (auto it = rem_markets.begin(); it != rem_markets.end(); ++it) {
                const auto &el = *it;
                sol.insert_market_at_pos(el.market_, el.position_);
            }
        }
    }
    LOG_F(INFO, "Final cost: %d", sol.cost_);
    if (solution_changed) {
        CHECK_F(is_solution_valid(instance, sol.route_),
                "Sol. should be valid");
    }
    return total_cost_change;
}
int k_exchange_heuristic ( const TPP :: Instance & instance , TPP :: Solution & sol , const uint32_t k ) { LOG_SCOPE_F ( INFO , " " ) ; LOG_F ( INFO , " " , sol . cost_ ) ; auto total_cost_change = 0 ; auto unselected = sol . get_unselected_markets ( ) ; auto solution_changed = false ; const auto route_copy = sol . route_ ; struct MarketPosition { size_t market_ { 0 } ; size_t position_ { 0 } ; bool operator < ( const MarketPosition & rhs ) { return this -> position_ < rhs . position_ ; ; } } ; vector < MarketPosition > rem_markets ; rem_markets . reserve ( k ) ; for ( auto i = 1u ; i + k - 1 < route_copy . size ( ) ; ++ i ) { const auto cost_before_removal = sol . cost_ ; rem_markets . clear ( ) ; for ( auto j = 0u ; j < k ; ++ j ) { const auto market = route_copy . at ( i + j ) ; const auto pos = sol . get_market_pos_in_route ( market ) ; rem_markets . push_back ( MarketPosition { market , pos } ) ; } sort ( begin ( rem_markets ) , end ( rem_markets ) ) ; for ( auto it = rem_markets . rbegin ( ) ; it != rem_markets . rend ( ) ; ++ it ) { const auto & el = * it ; sol . remove_market_at_pos ( el . position_ ) ; } bool found = false ; for ( auto cand : unselected ) { if ( ! sol . check_market_satisfies_demand ( cand ) ) { continue ; } const auto verdict = sol . calc_market_add_cost ( cand ) ; if ( sol . cost_ + verdict . cost_change_ < cost_before_removal && verdict . demand_satisfied_ ) { LOG_F ( INFO , " " , cand , verdict . cost_change_ , verdict . index_ ) ; const auto prev_cost = sol . cost_ ; total_cost_change += verdict . cost_change_ ; sol . insert_market_at_pos ( cand , verdict . index_ ) ; CHECK_F ( prev_cost + verdict . cost_change_ == sol . cost_ , " " , sol . cost_ ) ; LOG_F ( INFO , " " , sol . cost_ ) ; unselected . erase ( find ( begin ( unselected ) , end ( unselected ) , cand ) ) ; found = true ; break ; } } if ( found ) { solution_changed = true ; i += k - 1 ; } else { for ( auto it = rem_markets . begin ( ) ; it != rem_markets . end ( ) ; ++ it ) { const auto & el = * it ; sol . insert_market_at_pos ( el . market_ , el . position_ ) ; } } } LOG_F ( INFO , " " , sol . cost_ ) ; if ( solution_changed ) { CHECK_F ( is_solution_valid ( instance , sol . route_ ) , " " ) ; } return total_cost_change ; }
This is similar to the exchange_heuristic but drops k consecutive markets
 from the tour and tries to insert a single one from the unvisited.
This is similar to the exchange_heuristic but drops k consecutive markets from the tour and tries to insert a single one from the unvisited .
// Look for another market to insert // Skip over removed markets // Restore solution to the previous state