#pragma GCC optimize ("O3") #pragma GCC optimize ("unroll-loops") #pragma GCC target ("avx2") #include #include #include #include #include #include #include #include #include #include #include #include #include struct xorshift64 { unsigned long long int x = 88172645463325252ULL; inline unsigned short nextUShort() { x = x ^ (x << 7); return x = x ^ (x >> 9); } inline unsigned int nextUShortMod(unsigned long long int mod) { x = x ^ (x << 7); x = x ^ (x >> 9); return ((x & 0x0000ffffffffffff) * mod) >> 48; } inline unsigned int nextUInt() { x = x ^ (x << 7); return x = x ^ (x >> 9); } inline unsigned int nextUIntMod(unsigned long long int mod) { x = x ^ (x << 7); x = x ^ (x >> 9); return ((x & 0x00000000ffffffff) * mod) >> 32; } inline unsigned long long int nextULL() { x = x ^ (x << 7); return x = x ^ (x >> 9); } inline double nextDouble() { x = x ^ (x << 7); x = x ^ (x >> 9); return (double)x * 5.42101086242752217e-20; } }; struct timer { double t = 0.0; double lastStop = 0.0; bool stopped = false; timer() { restart(); } inline void restart() { t = now(); stopped = false; } inline void start() { if (stopped) { t += now() - lastStop; stopped = false; } } inline void stop() { if (!stopped) { lastStop = now(); stopped = true; } } inline double time() { if (stopped) return lastStop - t; else return now() - t; } inline double now() { unsigned long long l, h; __asm__ ("rdtsc" : "=a"(l), "=d"(h)); #ifdef LOCAL return (double)(l | h << 32) * 2.857142857142857e-10; // 1 / 3.5e9, for local (Ryzen 9 3950X) #else // return (double)(l | h << 32) * 3.5714285714285715e-10; // 1 / 2.8e9, for AWS EC2 C3 (Xeon E5-2680 v2) // return (double)(l | h << 32) * 3.4482758620689656e-10; // 1 / 2.9e9, for AWS EC2 C4 (Xeon E5-2666 v3) // return (double)(l | h << 32) * 3.333333333333333e-10; // 1 / 3.0e9, for AWS EC2 C5 (Xeon Platinum 8124M / Xeon Platinum 8275CL) return (double)(l | h << 32) * 4.3478260869565215e-10; // 1 / 2.3e9, for yukicoder judge #endif } }; using namespace std; typedef long long int ll; typedef unsigned long long int ull; typedef pair Pii; const ll mod = 1000000007; timer theTimer; xorshift64 theRandom; mt19937 theMersenne(1); // hyper parameters // enums // structs // constants constexpr int planet_num = 100; constexpr int station_num = 8; constexpr int planet_cost_factor = 5; // inputs vector planet_pos; // outputs vector station_pos; vector route_info; // internals vector > planet_to_planet_cost; vector > station_to_planet_cost; vector > station_to_station_cost; vector planet_visit_order; void receive_input() { int _n, _m; cin >> _n >> _m; planet_pos = vector(planet_num); for (auto &planet: planet_pos) cin >> planet.first >> planet.second; } void init_planet_to_planet_cost() { planet_to_planet_cost = vector >(planet_num, vector(planet_num)); for (int i = 0; i < planet_num; i++) { for (int j = i; j < planet_num; j++) { planet_to_planet_cost[i][j] = planet_cost_factor * planet_cost_factor * ((planet_pos[i].first - planet_pos[j].first) * (planet_pos[i].first - planet_pos[j].first) + (planet_pos[i].second - planet_pos[j].second) * (planet_pos[i].second - planet_pos[j].second)); planet_to_planet_cost[j][i] = planet_to_planet_cost[i][j]; } } } void init_station_to_planet_cost() { station_to_planet_cost = vector >(station_num, vector(planet_num)); for (int i = 0; i < station_num; i++) { for (int j = 0; j < planet_num; j++) { station_to_planet_cost[i][j] = planet_cost_factor * ((station_pos[i].first - planet_pos[j].first) * (station_pos[i].first - planet_pos[j].first) + (station_pos[i].second - planet_pos[j].second) * (station_pos[i].second - planet_pos[j].second)); } } } void init_station_to_station_cost() { station_to_station_cost = vector >(station_num, vector(planet_num)); for (int i = 0; i < station_num; i++) { for (int j = i; j < station_num; j++) { station_to_station_cost[i][j] = ((station_pos[i].first - station_pos[j].first) * (station_pos[i].first - station_pos[j].first) + (station_pos[i].second - station_pos[j].second) * (station_pos[i].second - station_pos[j].second)); station_to_station_cost[j][i] = station_to_station_cost[i][j]; } } } void init() { station_pos = vector(station_num); for (int i = 0; i < station_num; i++) { station_pos[i] = Pii(theRandom.nextUIntMod(801) + 100, theRandom.nextUIntMod(801) + 100); } { vector planet_cluster(planet_num); for (int i = 0; i < planet_num; i++) planet_cluster[i] = theRandom.nextUIntMod(station_num); vector next_planet_cluster = planet_cluster; int iter_count = 0; do { planet_cluster = next_planet_cluster; vector cluster_count(station_num); vector cluster_pos_sum(station_num); for (int i = 0; i < planet_num; i++) { cluster_count[planet_cluster[i]]++; cluster_pos_sum[planet_cluster[i]].first += planet_pos[i].first; cluster_pos_sum[planet_cluster[i]].second += planet_pos[i].second; } for (int i = 0; i < station_num; i++) { if (cluster_count[i] > 0) { station_pos[i] = Pii(cluster_pos_sum[i].first / cluster_count[i], cluster_pos_sum[i].second / cluster_count[i]); } } for (int i = 0; i < planet_num; i++) { int nearest_station = -1; int nearest_distance = 1000000007; for (int j = 0; j < station_num; j++) { int dist = (planet_pos[i].first - station_pos[j].first) * (planet_pos[i].first - station_pos[j].first) + (planet_pos[i].second - station_pos[j].second) * (planet_pos[i].second - station_pos[j].second); if (dist < nearest_distance) { nearest_station = j; nearest_distance = dist; } } next_planet_cluster[i] = nearest_station; } iter_count++; } while (planet_cluster != next_planet_cluster || iter_count < 100); } init_planet_to_planet_cost(); init_station_to_planet_cost(); init_station_to_station_cost(); planet_visit_order = vector(planet_num + 1); { planet_visit_order[0] = 0; planet_visit_order[planet_num] = 0; int current_planet = 0; vector visited(planet_num); visited[0] = true; for (int i = 1; i < planet_num; i++) { int best_planet = -1; int best_cost = 1000000007; for (int j = 0; j < planet_num; j++) { if (!visited[j] && planet_to_planet_cost[current_planet][j] < best_cost) { best_planet = j; best_cost = planet_to_planet_cost[current_planet][j]; } } planet_visit_order[i] = best_planet; current_planet = best_planet; visited[best_planet] = true; } } } vector find_shortest_route(int planet_from, int planet_to) { vector planet_visited(planet_num); vector station_visited(station_num); vector planet_prev_entity(planet_num); vector station_prev_entity(station_num); priority_queue, vector >, greater > > que; // cost, entity_type, entity_id, prev_entity_type, prev_entity_id que.emplace(0, 1, planet_from, 1, planet_from); while (!que.empty()) { auto [cost, entity_type, entity_id, prev_entity_type, prev_entity_id] = que.top(); que.pop(); if (entity_type == 1) { // planet if (planet_visited[entity_id]) continue; planet_visited[entity_id] = true; planet_prev_entity[entity_id] = Pii(prev_entity_type, prev_entity_id); if (entity_id == planet_to) { break; } for (int next_planet = 0; next_planet < planet_num; next_planet++) { if (!planet_visited[next_planet]) { que.emplace(cost + planet_to_planet_cost[entity_id][next_planet], 1, next_planet, entity_type, entity_id); } } for (int next_station = 0; next_station < station_num; next_station++) { if (!station_visited[next_station]) { que.emplace(cost + station_to_planet_cost[next_station][entity_id], 2, next_station, entity_type, entity_id); } } } else if (entity_type == 2) { // station if (station_visited[entity_id]) continue; station_visited[entity_id] = true; station_prev_entity[entity_id] = Pii(prev_entity_type, prev_entity_id); for (int next_planet = 0; next_planet < planet_num; next_planet++) { if (!planet_visited[next_planet]) { que.emplace(cost + station_to_planet_cost[entity_id][next_planet], 1, next_planet, entity_type, entity_id); } } for (int next_station = 0; next_station < station_num; next_station++) { if (!station_visited[next_station]) { que.emplace(cost + station_to_station_cost[entity_id][next_station], 2, next_station, entity_type, entity_id); } } } } vector route; int current_entity_type = 1; int current_entity_id = planet_to; while (!(current_entity_type == 1 && current_entity_id == planet_from)) { route.emplace_back(current_entity_type, current_entity_id); if (current_entity_type == 1) { // planet auto [prev_entity_type, prev_entity_id] = planet_prev_entity[current_entity_id]; current_entity_type = prev_entity_type; current_entity_id = prev_entity_id; } else if (current_entity_type == 2) { // station auto [prev_entity_type, prev_entity_id] = station_prev_entity[current_entity_id]; current_entity_type = prev_entity_type; current_entity_id = prev_entity_id; } } reverse(route.begin(), route.end()); return route; } void update_route_info() { route_info.emplace_back(1, 0); for (int i = 0; i < planet_num; i++) { auto path = find_shortest_route(planet_visit_order[i], planet_visit_order[i + 1]); for (auto &entity: path) route_info.push_back(entity); } } void solve() { vector > cost_from_to(planet_num + station_num, vector(planet_num + station_num)); auto update_cost = [&]() { for (int i = 0; i < planet_num + station_num; i++) { for (int j = 0; j < planet_num + station_num; j++) { if (i < planet_num && j < planet_num) cost_from_to[i][j] = planet_to_planet_cost[i][j]; else if (i < planet_num) cost_from_to[i][j] = station_to_planet_cost[j - planet_num][i]; else if (j < planet_num) cost_from_to[i][j] = station_to_planet_cost[i - planet_num][j]; else cost_from_to[i][j] = station_to_station_cost[i - planet_num][j - planet_num]; } } for (int k = 0; k < planet_num + station_num; k++) { for (int i = 0; i < planet_num + station_num; i++) { for (int j = 0; j < planet_num + station_num; j++) { if (cost_from_to[i][k] + cost_from_to[k][j] < cost_from_to[i][j]) cost_from_to[i][j] = cost_from_to[i][k] + cost_from_to[k][j]; } } } }; update_cost(); { auto calc_score = [&]() { int score = 0; for (int i = 0; i < planet_num; i++) score += cost_from_to[planet_visit_order[i]][planet_visit_order[i+1]]; return score; }; int score = calc_score(); int last_score = score; int best_score = score; const double base_temperature = 1e4; const double target_temperature = 1e2; // const double decay_rate = 4e-5; double temperature = base_temperature; double time_start = theTimer.time(); const double time_limit = 0.980; int iter_count = 0; while (theTimer.time() < time_limit) { double roll = theRandom.nextDouble(); if (roll < 0.99) { int p1 = theRandom.nextUIntMod(planet_num - 1) + 1; int p2 = theRandom.nextUIntMod(planet_num - 1) + 1; if (p1 == p2) continue; swap(planet_visit_order[p1], planet_visit_order[p2]); score = calc_score(); #ifdef DEBUG if (iter_count % 1000 == 0) cerr << iter_count << " " << score << " " << last_score << " " << best_score << " " << temperature << " " << theTimer.time() << endl; #endif if (score <= last_score) { last_score = score; if (score < best_score) { best_score = score; } } else if (theRandom.nextDouble() < exp(double(last_score - score) / temperature)) { // accept last_score = score; } else { // rollback swap(planet_visit_order[p1], planet_visit_order[p2]); score = last_score; } } else if (roll < 1.00) { int s = theRandom.nextUIntMod(station_num); int dx = theRandom.nextUIntMod(101) - 50; int dy = theRandom.nextUIntMod(101) - 50; if (dx == 0 && dy == 0) continue; if (!(0 <= station_pos[s].first + dx && station_pos[s].first + dx <= 1000) || !(0 <= station_pos[s].second + dy && station_pos[s].second + dy <= 1000)) continue; station_pos[s].first += dx; station_pos[s].second += dy; init_station_to_planet_cost(); init_station_to_station_cost(); update_cost(); score = calc_score(); #ifdef DEBUG if (iter_count % 1000 == 0) cerr << iter_count << " " << score << " " << last_score << " " << best_score << " " << temperature << " " << theTimer.time() << endl; #endif if (score <= last_score) { last_score = score; if (score < best_score) { best_score = score; } } else if (theRandom.nextDouble() < exp(double(last_score - score) / temperature)) { // accept last_score = score; } else { // rollback station_pos[s].first -= dx; station_pos[s].second -= dy; init_station_to_planet_cost(); init_station_to_station_cost(); update_cost(); score = last_score; } } // temperature *= 1.0 - decay_rate; temperature = exp(log(base_temperature) - ((log(base_temperature) - log(target_temperature)) * ((theTimer.time() - time_start) * (1.0 / (time_limit - time_start))))); iter_count++; } cerr << "iter_count = " << iter_count << endl; cerr << "score = " << score << endl; cerr << "best_score = " << best_score << endl; cerr << "temperature = " << temperature << endl; } update_route_info(); } void output_ans() { for (auto &station: station_pos) { cout << station.first << " " << station.second << endl; } cout << route_info.size() << endl; for (auto &route: route_info) { cout << route.first << " " << route.second + 1 << endl; } } int main(int argc, char *argv[]) { cin.tie(0); ios::sync_with_stdio(false); receive_input(); init(); solve(); output_ans(); return 0; }