#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 = 900; constexpr ll INF = 1e9; // simulated annealing constexpr double temp_start = 1.0; constexpr double temp_end = 0.00001; constexpr int climb_loop = 1000000; 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; } 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; // two opt rep(cn,climb_loop) { if(timer.get_ms() > time_limit) break; double temp = temp_start + (temp_end - temp_start)*cn/climb_loop; 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 = (dpp[seq[t]][seq[s-1]] + dpp[seq[s]][seq[t+1]] - dpp[seq[s]][seq[s-1]] - dpp[seq[t]][seq[t+1]])*A*A; if(score_diff < 0 || uniform_01(eng) < exp((double)-score_diff/temp)) { score += score_diff; reverse(seq.begin()+s,seq.begin()+t+1); if(score < best_score) { best_score = score; best_seq = seq; } } } // 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; } 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; }