#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define REP(i,m,n) for(int i=int(m);i=int(m);--i) #define EACH(i,c) for (auto &(i): c) #define all(c) begin(c),end(c) #define EXIST(s,e) ((s).find(e)!=(s).end()) #define SORT(c) sort(begin(c),end(c)) #define pb emplace_back #define MP make_pair #define SZ(a) int((a).size()) //#define int long long #ifdef LOCAL #define DEBUG(s) cout << (s) << endl #define dump(x) cerr << #x << " = " << (x) << endl #define BR cout << endl; #else #define DEBUG(s) do{}while(0) #define dump(x) do{}while(0) #define BR #endif using namespace std; using UI = unsigned int; using UL = unsigned long; using LL = long long; using ULL = unsigned long long; using VI = vector; using VVI = vector; using VLL = vector; using VVLL = vector; using VS = vector; using PII = pair; using VP = vector; template using V = vector; templatebool chmax(T &a, const T &b) { if (abool chmin(T &a, const T &b) { if (b::max()/2; //constexpr int MOD = 1'000'000'007; //inline void modAdd(LL &l, LL &r) {l = (l + r) % MOD;} template inline T sqr(T x) {return x*x;} long double sqrt(int v) {return sqrt((long double)v);} long double sqrt(long long v) {return sqrt((long double)v);} constexpr double baseTimeLimit = 0.975; #ifdef LOCAL constexpr int timemul = 1; #else constexpr int timemul = 1; #endif constexpr double timeLimit = baseTimeLimit * timemul; constexpr int alpha = 5; double diff(const chrono::system_clock::time_point &st) { return chrono::duration_cast(chrono::system_clock::now() - st).count() * 1e-6; } unsigned int xor96(void) { static unsigned int x = 123456789; static unsigned int y = 362436069; static unsigned int z = 521288629; unsigned int t; t = (x ^ (x << 3)) ^ (y ^ (y >> 19)) ^ (z ^ (z << 6)); x = y; y = z; return z = t; } class State { public: LL score; // VLL scores; int m; VI c,d; VI usedCnt; VVLL pd; VVLL sd; State(const State&) = default; State(State&&) = default; State& operator=(const State&) = default; State& operator=(State&&) = default; State(int m): score(0), m(m), c(m), d(m), usedCnt(m) { REP(i,0,m) { c[i] = xor96() % 1001; d[i] = xor96() % 1001; } } void init(int n, const VI &a, const VI &b) { pd = VVLL(n,VLL(n)); sd = VVLL(m,VLL(n)); REP(i,0,n) REP(j,i,n) { pd[i][j] = pd[j][i] = 1LL * (sqr(a[i]-a[j]) + sqr(b[i]-b[j])) * sqr(alpha); } REP(i,0,m) REP(j,0,n) { sd[i][j] = 1LL * (sqr(c[i]-a[j]) + sqr(d[i]-b[j])) * sqr(alpha); } score = calcScore(n,a,b); } LL calcScore(int n, const VI &a, const VI &b) { LL score = 0; REP(i,0,m) usedCnt[i] = 0; VI visited(n); int idx = 0, cnt = 0; while (cnt < n) { ++cnt; visited[idx] = true; int dst = -1; LL d = 1LL<<60; REP(i,0,n) { if (visited[i]) continue; if (chmin(d, calcShortest(idx,i))) { dst = i; } } if (dst > -1) idx = dst; } score += calcShortest(idx,0); return score; } State modify(int n, const VI &a, const VI &b) { // 選択・分岐処理 int r = xor96() % 2; int idx = xor96() % m; VI unused; REP(i,0,m) if (usedCnt[i] == 0) unused.push_back(i); if (!unused.empty()) { idx = unused[xor96()%unused.size()]; } State newState(*this); if (r % 2) newState.modifyX(n,a,b,idx); else newState.modifyY(n,a,b,idx); return newState; } void print(int n, const VI &a, const VI &b) { REP(i,0,m) { cout << c[i] << " " << d[i] << endl; } VI visited(n); int idx = 0, cnt = 0; VI path; while (cnt < n) { ++cnt; visited[idx] = true; path.push_back(idx); int dst = -1; LL d = 1LL<<60; REP(i,0,n) { if (visited[i]) continue; if (chmin(d, calcShortest(idx,i))) { dst = i; } } if (dst > -1) idx = dst; } path.push_back(0); VP ps = {{1,0}}; REP(i,1,path.size()) { int mid = -1; long long ret = pd[path[i-1]][path[i]]; REP(j,0,m) { if (chmin(ret, sd[j][path[i-1]] + sd[j][path[i]])) { mid = i; } } if (mid > -1) { ps.pb(2,mid); } ps.pb(1,path[i]); } cout << ps.size() << endl; for (auto [t,r]: ps) { cout << t << " " << r + 1 << endl; } } private: long long calcShortest(int s, int t) { long long ret = pd[s][t]; int mid = -1; REP(i,0,m) { if (chmin(ret, sd[i][s] + sd[i][t])) { mid = i; } } if (mid > -1) usedCnt[mid]++; return ret; } void modifyX(int n, const VI &a, const VI &b, int idx) { int dist = xor96() % 1000 - 500; c[idx] = max(0,min(1000,c[idx]+dist)); REP(j,0,n) { sd[idx][j] = 1LL * (sqr(c[idx]-a[j]) + sqr(d[idx]-b[j])) * sqr(alpha); } score = calcScore(n,a,b); } void modifyY(int n, const VI &a, const VI &b, int idx) { int dist = xor96() % 1000 - 500; d[idx] = max(0,min(1000,d[idx]+dist)); REP(j,0,n) { sd[idx][j] = 1LL * (sqr(c[idx]-a[j]) + sqr(d[idx]-b[j])) * sqr(alpha); } score = calcScore(n,a,b); } }; // 焼きなまし法 State sa(int n, int m, const VI &a, const VI &b, double start_temp, double end_temp, double TIME_LIMIT) { State state(m); state.init(n,a,b); //int times = 0; chrono::system_clock::time_point st = chrono::system_clock::now(); int cnt = 0; double dt; while ((dt = diff(st)) < TIME_LIMIT) { // 時間の許す限り回す REP(loop,0,10) { State new_state = state.modify(n,a,b); int new_score = new_state.score; int pre_score = state.score; // 温度関数 double temp = start_temp + (end_temp - start_temp) * dt / TIME_LIMIT; // 遷移確率関数 double prob = exp(-((double)(new_score-pre_score))/temp); // 最小値 // double prob = exp(((double)(new_score-pre_score))/temp); // 最大値 if (prob > (xor96()%0xffffffffu)/(double)0xffffffffu) { // 確率probで遷移する state = new_state; } } ++cnt; dump(state.score); } dump(cnt); return state; } void solve() { auto st = chrono::system_clock::now(); int r = random_device()() % 1000; REP(i,0,r) xor96(); int n,m; cin >> n >> m; VI a(n),b(n); REP(i,0,n) cin >> a[i] >> b[i]; int times = 2; auto state = sa(n,m,a,b,1000,100,timeLimit/times); REP(i,1,times) { auto state2 = sa(n,m,a,b,1000,100,timeLimit/times); if (state2.score < state.score) { state = move(state2); } } dump(state.score); state.print(n,a,b); } signed main() { int t = 1; // cin >> t; REP(i,0,t) { solve(); } return 0; }