#include #ifdef LOCAL #include #define debug(...) debug_print::multi_print(#__VA_ARGS__, __VA_ARGS__) #else #define debug(...) (static_cast(0)) #endif using namespace std; using ll=long long; // Start 2023.04.23 21:00 // End // Time min // MTK005 constexpr ll TYPE_PLANET = 1; constexpr ll TYPE_STATION = 2; constexpr ll ALPHA = 5; constexpr ll INF = (1LL << 60); ll START_TIME = 0; struct Pos { int x,y; ll type; Pos(int x, int y, ll type) : x(x), y(y), type(type) {} }; std::ostream& operator<<(std::ostream& os, const Pos& pos) { std::ostringstream oss; oss << "(" << pos.x << ", " << pos.y << "), " << pos.type << ""; os << oss.str(); return os; } struct Solver { int N = 0; int M = 0; vector points; Solver(int n, int m, vector& points) : N(n),M(m),points(points) {} void test() { debug(N,M,points); } void solve() { // 貪欲法 set_station(); // debug(points); // 全点間エネルギーを計算 vector> distances = calc_distance(); // 惑星1からスタートする // 一番近い惑星+宇宙ステーションを選び続ける vector route = greedy(distances); debug(route); double limit1 = 0.1; double limit2 = 0.93-limit1; // 宇宙ステーションを1つ選んでずらす { double current_score = calc_score(route); int ti = clock(); int TIMELIMIT = limit1 * CLOCKS_PER_SEC; int cnt = 1; int kaizen = 0; int random = 0; while(clock() - ti < TIMELIMIT) { // debug(clock()-ti,__LINE__,cnt); cnt++; // ずらす宇宙ステーションをランダムに選ぶ int num = RandInt(N,N+M-1); // debug(num,points.size()); vector old_points = points; // vector new_points = points; Pos pos = points[num]; int diff = 20; int x = min(max(0,pos.x+RandInt(diff*(-1),diff)),1000); int y = min(max(0,pos.y+RandInt(diff*(-1),diff)),1000); // int x = RandInt(50,950); // int y = RandInt(50,950); // debug(x,y); // debug(clock()-ti,__LINE__); // points.erase(points.begin() + num); // points.insert(points.begin() + num, Pos(x,y,TYPE_STATION)); points[num] = Pos(x,y,TYPE_STATION); // debug(clock()-ti,__LINE__); vector> old_distances = distances; // debug(clock()-ti,__LINE__); distances = update_distance(distances, num); // debug(clock()-ti,__LINE__); // vector new_route = greedy(distances); // debug(clock()-ti,__LINE__); // double new_score = calc_score(new_route); double new_score = calc_score(route); // debug(clock()-ti,__LINE__); double T = 30.00 - 29.00 * cnt / 10000.0; double probability = exp(min(0.0, (current_score - new_score)/T)); // if(Randouble() < probability) { if(current_score <= new_score) { // if(current_score <= new_score) { // random++; // } kaizen++; current_score = new_score; // distances = new_distances; // route = new_route; } else { // 元に戻す distances = old_distances; points = old_points; } } // debug(clock()-ti,__LINE__); debug(cnt,kaizen, kaizen*100/cnt,kaizen-random); } // 2-opt { double current_score = calc_score(route); int ti = clock(); // int TIMELIMIT = 0.93 * CLOCKS_PER_SEC; int TIMELIMIT = limit2 * CLOCKS_PER_SEC; int cnt = 1; int kaizen = 0; int random = 0; while(clock() - ti < TIMELIMIT) { // for(int t=1; t<400000; t++) { cnt++; int l = RandInt(1,route.size()-2); int r = RandInt(1,route.size()-2); while(l == r) { l = RandInt(1,route.size()-2); r = RandInt(1,route.size()-2); } if(l > r) swap(l,r); if(calc_energy(route[l],route[r]) + calc_energy(route[l+1],route[r+1]) < calc_energy(route[l],route[l+1]) + calc_energy(route[l],route[r+1])) { for(int k=0; k<(r-l)/2; k++) { swap(route[l+1+k],route[r-k]); } } double new_score = calc_score(route); // debug(new_score); double T = 30.00 - 28.00 * cnt / 40000.0; double probability = exp(min(0.0, (current_score - new_score)/T)); // if(current_score <= new_score && Randouble() < probability) { // if(current_score <= new_score) { if(Randouble() < probability) { if(current_score <= new_score) { random++; } kaizen++; current_score = new_score; } else { // 元に戻す for(int k=0; k<(r-l)/2; k++) { swap(route[l+1+k],route[r-k]); } } } debug(cnt,kaizen, kaizen*100/cnt,kaizen-random); } // debug(route); output(route); calc_score(route); } vector> calc_distance() { // 全点間エネルギーを計算 vector> distances(N+M,vector(N+M)); for(int i=0; i> update_distance(vector>& distances, int k) { // 全点間エネルギーを計算 // vector> distances(N+M,vector(N+M)); // for(int i=0; i greedy(vector>& distances) { // 惑星1からスタートする // 一番近い惑星+宇宙ステーションを選び続ける vector visited(N+M,0); vector route; visited[0]++; route.push_back(0); int v = 0; for(int i=0; i 0) continue; // int d = calc_energy(v,next); int d = distances[v][next]; if(d < nearest_dist) { nearest_dist = d; nearest_v = next; } // debug(d); } // 次の頂点に移動 // dijkstraで経路を復元 vector path = djikstra(v,nearest_v); for(auto p : path) { route.push_back(p); } v = nearest_v; visited[v]++; // route.push_back(nearest_v); } // 最後に惑星1に戻る route.push_back(0); // debug(visited); // debug(route); return route; } vector update_greedy(vector>& distances, vector& route, int k) { // 全部通ってるところから vector visited(N+M,1); // 消した宇宙ステーションを削除する visited[k] = 0; vector new_route = route; for(int i=0; i route; // visited[0]++; // route.push_back(0); int v = 0; for(int i=0; i 0) continue; // int d = calc_energy(v,next); int d = distances[v][next]; if(d < nearest_dist) { nearest_dist = d; nearest_v = next; } // debug(d); } // 次の頂点に移動 // dijkstraで経路を復元 vector path = djikstra(v,nearest_v); for(auto p : path) { route.push_back(p); } v = nearest_v; visited[v]++; // route.push_back(nearest_v); } // 最後に惑星1に戻る route.push_back(0); // debug(visited); // debug(route); return route; } void output(vector& route) { // 宇宙ステーションの座標 for(int i=N; i> v; v.push_back({300,300}); v.push_back({300,500}); v.push_back({300,700}); v.push_back({500,300}); v.push_back({500,700}); v.push_back({700,300}); v.push_back({700,500}); v.push_back({700,700}); for(int i=0; i& route, vector>& distances) { debug(route.size()); for(int i=1; i& route) { ll s = 0; for(int i=0; i djikstra(int i, int j) { // 二点間の最短距離 // vector> dij(N+M); // 経路復元用 1つ前にいた頂点を保存 vector prev_points(N+M,-1); // int k = 0; // for(int k=0; k cur(N+M,INF); vector kakutei(N+M+1,false); priority_queue, vector>, greater>> Q; int start = i; cur[start] = 0; Q.push(make_pair(cur[start],start)); while(!Q.empty()) { auto[d, pos] = Q.top(); Q.pop(); if(kakutei[pos] == true) continue; kakutei[pos] = true; for(int next=0; next cur[pos]+cost) { // 1つ前の点を保存 prev_points[next] = pos; // 値を更新 cur[next] = cur[pos]+cost; Q.push(make_pair(cur[next],next)); } } } // dij[i] = cur; // } // debug(dij); // debug(cur); // debug(prev_points); // 経路復元 // ゴールからたどっていく int v = j; vector path; while(v != i) { path.push_back(v); v = prev_points[v]; } reverse(path.begin(),path.end()); return path; } }; int main() { START_TIME = clock(); int n,m; cin >> n >> m; // vector a(n),b(n); vector points; for(int i=0; i> a >> b; points.emplace_back(Pos(a,b,TYPE_PLANET)); } debug(n,m,points); Solver solver(n,m,points); solver.solve(); return 0; }