#pragma GCC target("avx2") #pragma GCC optimize("O3") #pragma GCC optimize("unroll-loops") #include //#include using namespace std; //using namespace atcoder; template T sum(vector& array) { return accumulate(array.begin(), array.end(), (T)0); } template int index(vector& data, T element) { return distance(data.begin(), find(data.begin(),data.end(),element)); } template int contain(vector& data, T element) { return !(index(data, element) == (int)data.size()); } struct Randomizer { mt19937_64 engine; uniform_int_distribution<> dist = uniform_int_distribution<>(0, INT_MAX); Randomizer() { random_device seed_gen; engine = mt19937_64(seed_gen()); } Randomizer(int seed) { engine = mt19937_64(seed); } double uniform(double l, double r) { assert(l <= r); return l + (r-l)*dist(engine)/INT_MAX; } int randrange(int l, int r) { assert(l < r); return l + dist(engine)%(r-l); } template T choice(vector& data) { return data.at(randrange(0, data.size())); } vector sample(int l, int r, int num) { assert(0 < num && num <= r - l); vector ret; while ((int)ret.size() < num) { int x = randrange(l, r); if (!contain(ret, x)) { ret.push_back(x); } } sort(ret.begin(), ret.end()); return ret; } }; struct Timer { timespec start; Randomizer randomizer; Timer() {} Timer(int seed) { randomizer = Randomizer(seed); } void begin() { clock_gettime(CLOCK_REALTIME, &start); } double stopwatch() { timespec end; clock_gettime(CLOCK_REALTIME, &end); double sec = end.tv_sec - start.tv_sec; double nsec = end.tv_nsec - start.tv_nsec; return sec + nsec/1000000000; } bool scheduler(double delta, double time_limit, double t0, double t1) { assert(0.0 < time_limit && 0.0 <= t1 && t1 <= t0); if (0.0 <= delta) { return true; } else { double ratio = stopwatch() / time_limit; double t = pow(t0, 1.0-ratio) * pow(t1, ratio); return randomizer.uniform(0.0, 1.0) < pow(2.0, delta/t); } } }; vector tsp_solver(vector> cost_matrix) { // n を始点および終点とするTSPの厳密解を求める. int n = cost_matrix.size() - 1; int s = n; int inf = 1 << 30; // dp vector> dp(n, vector(1<>i & 1) == 0) { continue; } for (int j = 0; j < n; j++) { if (mask>>j & 1) { continue; } dp[j][mask^(1< ret = {last}; int mask = (1<>i & 1 && dp[i][mask] + cost_matrix[i][j] == dp[j][mask^1< a, b; vector> groups; vector c, d; Solver() { timer.begin(); } void input() { cin >> n >> m; a = vector(n); b = vector(n); for (int i = 0; i < n; i++) { cin >> a[i] >> b[i]; } } pair get_center(vector& group) { if (group.empty()) { int j = randomizer.randrange(0, n); return {a[j], b[j]}; } int x = 0; int y = 0; for (int i : group) { x += a[i]; y += b[i]; } return {x/(int)group.size(), y/(int)group.size()}; } void k_means() { groups = vector>(m); for (int i = 0; i < m; i++) { groups[i].push_back(i); } for (int i = m; i < n; i++) { groups[randomizer.randrange(0,m)].push_back(i); } while (true) { vector> centers(m); for (int i = 0; i < m; i++) { centers[i] = get_center(groups[i]); } vector> new_groups(m); for (int i = 0; i < n; i++) { int best = 0; int min_cost = inf; for (int j = 0; j < m; j++) { auto [x, y] = centers[j]; int cost = (a[i]-x)*(a[i]-x) + (b[i]-y)*(b[i]-y); if (cost < min_cost) { best = j; min_cost = cost; } } new_groups[best].push_back(i); } if (groups == new_groups) { break; } groups = new_groups; } } void solve() { k_means(); c = vector(m); d = vector(m); for (int i = 0; i < m; i++) { pair p = get_center(groups[i]); c[i] = p.first; d[i] = p.second; } vector> cost_matrix(m, vector(m)); for (int i = 0; i < m; i++) { for (int j = 0; j < m; j++) { int dist = (c[i]-c[j])*(c[i]-c[j]) + (d[i]-d[j])*(d[i]-d[j]); cost_matrix[i][j] = dist; cost_matrix[j][i] = dist; } } vector order = tsp_solver(cost_matrix); int start = -1; for (int i = 0; i < m; i++) { if (contain(groups[i], 0)) { start = i; } } vector new_order(m); for (int i = 0; i < m; i++) { new_order[i] = order[(start+i) % m]; } order = new_order; for (int i = 0; i < m; i++) { cout << c[i] << ' ' << d[i] << '\n'; } cout << 2*n + m + 1 << '\n'; for (int i = 0; i < m; i++) { int station = order[i]; for (int star : groups[station]) { cout << 1 << ' ' << star + 1 << '\n'; cout << 2 << ' ' << station + 1 << '\n'; } cout << 2 << ' ' << order[(i+1) % m] + 1 << '\n'; } cout << 1 << ' ' << 1 << '\n'; } }; int main() { Solver solver; solver.input(); solver.solve(); return 0; }