#include #include using namespace atcoder; using namespace std; #define rep(i,n) for(int i = 0; i < (int)n; i++) using ll = long long; using P = pair; constexpr int N = 100; constexpr int M = 8; constexpr ll A = 5; constexpr int time_limit = 950; constexpr ll INF = 1e9; // simulated annealing constexpr double temp_start = 10.0; constexpr double temp_end = 0.00001; constexpr int climb_loop = 1e7; ll a[N], b[N]; // random int seed = 12345; mt19937 eng(seed); uniform_real_distribution<> uniform_01; // timer class Timer { private: chrono::system_clock::time_point start; public: Timer() { start = chrono::system_clock::now(); } int get_ms() { auto end = chrono::system_clock::now(); auto t = chrono::duration_cast(end-start).count(); return t; } }; vector

clustering() { vector

point; rep(i,N) point.push_back(P(a[i],b[i])); while(point.size() > M) { int psz = point.size(); ll dm = INF; int p1 = -1, p2 = -1; rep(i,psz) for(int j = i+1; j < psz; j++) { ll dx = point[i].first-point[j].first; ll dy = point[i].second-point[j].second; ll dist = dx*dx + dy*dy; if(dist < dm) { dm = dist; p1 = i; p2 = j; } } vector

point_new; rep(i,psz) if(i != p1 and i != p2) point_new.push_back(point[i]); point_new.push_back(P((point[p1].first+point[p2].first)/2,(point[p1].second+point[p2].second)/2)); swap(point,point_new); } return point; } void solve() { Timer timer; // input int hello; cin >> hello >> hello; rep(i,N) cin >> a[i] >> b[i]; vector> dpp(N,vector(N)); rep(i,N) rep(j,N) { ll dx = a[i]-a[j], dy = b[i]-b[j]; dpp[i][j] = dx*dx + dy*dy; } // clustering vector

pg = clustering(); vector> dpm(N,vector(M)); rep(i,N) rep(j,M) { ll dx = a[i]-pg[j].first, dy = b[i]-pg[j].second; dpm[i][j] = dx*dx + dy*dy; } vector> dmm(M,vector(M)); rep(i,M) rep(j,M) { ll dx = pg[i].first-pg[j].first, dy = pg[i].second-pg[j].second; dmm[i][j] = dx*dx + dy*dy; } vector seq(N+1); rep(i,N) seq[i] = i; seq[N] = 0; ll score = 0; for(int u = 1; u <= N; u++) score += dpp[seq[u]][seq[u-1]]*A*A; // best sequence ll best_score = score; vector best_seq = seq; auto calc_dist = [&](int u, int v) -> ll { ll res = dpp[u][v]*A*A; // via one station vector mu, mv; rep(j,M) { if(dpm[u][j]*A < res) mu.push_back(j); if(dpm[v][j]*A < res) mv.push_back(j); ll d1 = dpm[u][j]*A + dpm[v][j]*A; if(d1 < res) res = d1; } // vis two station for(auto j : mu) { for(auto k : mv) { ll d2 = dpm[u][j]*A + dmm[j][k] + dpm[v][k]*A; if(d2 < res) res = d2; } } return res; }; constexpr int SIGMA = 50; constexpr int PROP = 20; normal_distribution<> nd(0,SIGMA); auto update_dpm = [&](int s) { rep(i,N) { ll dx = a[i]-pg[s].first, dy = b[i]-pg[s].second; dpm[i][s] = dx*dx + dy*dy; } }; auto update_dmm = [&](int s) { rep(i,M) { ll dx = pg[i].first-pg[s].first, dy = pg[i].second-pg[s].second; dmm[i][s] = dx*dx + dy*dy; dmm[s][i] = dx*dx + dy*dy; } }; int last = 0; // two opt with clustering + move cluster point rep(cn,climb_loop) { if(timer.get_ms() > time_limit) break; double temp = temp_start + (temp_end - temp_start)*cn/climb_loop; int id = eng() % PROP; if(id) { // 経路変更 int s = eng() % (N-1) + 1; int t = eng() % (N-1) + 1; if(s == t) continue; if(s > t) swap(s,t); ll score_diff = calc_dist(seq[t],seq[s-1]) + calc_dist(seq[s],seq[t+1]) - calc_dist(seq[s],seq[s-1]) - calc_dist(seq[t],seq[t+1]); if(score_diff < 0 || uniform_01(eng) < exp((double)-score_diff/temp)) { score += score_diff; reverse(seq.begin()+s,seq.begin()+t+1); } } else { // 位置変更 int dx = nd(eng); int dy = nd(eng); if(dx == 0 and dy == 0) continue; int s = eng() % M; pg[s].first += dx; pg[s].second += dy; update_dpm(s); update_dmm(s); ll score_new = 0; for(int i = 1; i <= N; i++) score_new += calc_dist(seq[i-1],seq[i]); ll score_diff = score_new - score; if(score_diff < 0 || uniform_01(eng) < exp((double)-score_diff/temp)) { score += score_diff; } else { pg[s].first -= dx; pg[s].second -= dy; update_dpm(s); update_dmm(s); } } if(score < best_score) { last = timer.get_ms(); best_score = score; best_seq = seq; } } // 復元 ll score_cluster = 0; vector

seq_cluster; seq_cluster.push_back(P(1,0)); // consider clustering for(int i = 1; i <= N; i++) { ll res = dpp[best_seq[i]][best_seq[i-1]]*A*A; ll s1 = -1, s2 = -1; // via one station rep(j,M) { ll d1 = dpm[best_seq[i-1]][j]*A + dpm[best_seq[i]][j]*A; if(d1 < res) { res = d1; s1 = j; } } // vis two station rep(j,M) rep(k,M) { ll d2 = dpm[best_seq[i-1]][j]*A + dmm[j][k] + dpm[best_seq[i]][k]*A; if(d2 < res) { res = d2; s1 = j; s2 = k; } } score_cluster += res; if(s1 == -1 and s2 == -1) { seq_cluster.push_back(P(1,best_seq[i])); } else if(s1 != -1 and s2 == -1) { seq_cluster.push_back(P(2,s1)); seq_cluster.push_back(P(1,best_seq[i])); } else { seq_cluster.push_back(P(2,s1)); seq_cluster.push_back(P(2,s2)); seq_cluster.push_back(P(1,best_seq[i])); } } int final_score = round(1e9/(1000.0+sqrt((double)score_cluster))); // cerr << best_score << endl; cerr << "Time " << timer.get_ms() << endl; cerr << "Score = " << final_score << endl; rep(i,M) cout << pg[i].first << " " << pg[i].second << endl; cout << seq_cluster.size() << endl; for(auto [t, v] : seq_cluster) cout << t << " " << v+1 << endl; } int main() { solve(); return 0; }