結果

問題 No.5007 Steiner Space Travel
ユーザー hotpepsihotpepsi
提出日時 2023-04-29 13:40:46
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 972 ms / 1,000 ms
コード長 5,206 bytes
コンパイル時間 1,686 ms
コンパイル使用メモリ 116,980 KB
実行使用メモリ 4,376 KB
スコア 7,828,102
最終ジャッジ日時 2023-04-29 13:41:21
合計ジャッジ時間 33,870 ms
ジャッジサーバーID
(参考情報)
judge12 / judge14
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 963 ms
4,368 KB
testcase_01 AC 953 ms
4,372 KB
testcase_02 AC 941 ms
4,372 KB
testcase_03 AC 968 ms
4,368 KB
testcase_04 AC 952 ms
4,368 KB
testcase_05 AC 960 ms
4,368 KB
testcase_06 AC 962 ms
4,372 KB
testcase_07 AC 966 ms
4,368 KB
testcase_08 AC 964 ms
4,372 KB
testcase_09 AC 939 ms
4,368 KB
testcase_10 AC 960 ms
4,372 KB
testcase_11 AC 959 ms
4,368 KB
testcase_12 AC 971 ms
4,372 KB
testcase_13 AC 946 ms
4,368 KB
testcase_14 AC 942 ms
4,372 KB
testcase_15 AC 962 ms
4,368 KB
testcase_16 AC 951 ms
4,368 KB
testcase_17 AC 963 ms
4,372 KB
testcase_18 AC 961 ms
4,372 KB
testcase_19 AC 933 ms
4,368 KB
testcase_20 AC 958 ms
4,376 KB
testcase_21 AC 944 ms
4,368 KB
testcase_22 AC 954 ms
4,372 KB
testcase_23 AC 972 ms
4,372 KB
testcase_24 AC 930 ms
4,372 KB
testcase_25 AC 963 ms
4,368 KB
testcase_26 AC 938 ms
4,368 KB
testcase_27 AC 971 ms
4,372 KB
testcase_28 AC 958 ms
4,372 KB
testcase_29 AC 945 ms
4,372 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <sstream>
#include <cassert>
#include <cmath>
#include <cstring>
#include <chrono>
#include <algorithm>
#include <numeric>
#include <vector>
#include <queue>
#include <string>
#include <set>
#include <map>
#include <unordered_map>
#include <random>

using namespace std;

#if defined(_MSC_VER) || defined(__APPLE_CC__)
#define LOCAL
#endif

const int TIME_LIMIT = 6000 - 100;
const int INF = 1000000000;

typedef pair<int, int> II;

std::random_device seed_gen;
std::mt19937_64 engine(seed_gen());

auto start_time = chrono::high_resolution_clock::now();
inline int get_elapsed_ms() { return int(chrono::duration_cast<chrono::milliseconds>(chrono::high_resolution_clock::now() - start_time).count()); }

struct Solver {
	int N;
	int M;
	vector<int> y, x, g;

	void input() {
		cin >> N >> M;
		y.resize(N + M);
		x.resize(N + M);
		g.resize(N + M);
		for (int i = 0; i < N; ++i) {
			cin >> y[i] >> x[i];
		}
	}

	void prepare() {

	}

	int64_t get_dist(int a, int b) {
		int dx = x[b] - x[a], dy = y[b] - y[a];
		int64_t dist = dx * dx + dy * dy;
		if (a < N) dist *= 5;
		if (b < N) dist *= 5;
		return dist;
	}

	void output(const vector<int>& ans) {
		for (int i = 0; i < M; ++i) {
			cout << y[i + N] << " " << x[i + N] << endl;
		}
		cout << ans.size() << endl;
		for (int x : ans) {
			if (x < N) {
				cout << "1 " << (x + 1) << endl;
			} else {
				cout << "2 " << (x - N + 1) << endl;
			}
		}
	}

	bool classify() {
		for (int i = 0; i < N; ++i) {
			g[i] = engine() % M;
		}
		bool done = false;
		while (!done) {
			done = true;
			vector<int> xx(M), yy(M), cnt(M);
			for (int i = 0; i < N; ++i) {
				xx[g[i]] += x[i];
				yy[g[i]] += y[i];
				cnt[g[i]] += 1;
			}
			for (int i = 0; i < M; ++i) {
				if (cnt[i]) {
					xx[i] /= cnt[i];
					yy[i] /= cnt[i];
					x[N + i] = xx[i];
					y[N + i] = yy[i];
				}
			}
			for (int i = 0; i < N; ++i) {
				int md = INF, next_g = -1;
				for (int j = 0; j < M; ++j) {
					int dx = x[i] - xx[j], dy = y[i] - yy[j], d = dx * dx + dy * dy;
					if (d < md) {
						md = d;
						next_g = j;
					}
				}
				if (g[i] != next_g) {
					done = false;
					g[i] = next_g;
				}
			}
		}
		vector<int> cnt(M);
		for (int i = 0; i < N; ++i) {
			cnt[g[i]] += 1;
		}
		for (int i = 0; i < M; ++i) {
			if (cnt[i] == 0) {
				return false;
			}
		}
		return true;
	}

	vector<int> gen(int prev_point, int group, const vector<int>& points) {
		vector<int> r;
		if (points.size() > 60) {
			return r;
		}
		vector<int> closest_points(points.size());
		for (int i = 0; i < points.size(); ++i) {
			int64_t min_dist = 1LL << 60;
			int& closest = closest_points[i];
			for (int j = 0; j < points.size(); ++j) {
				if (i == j) continue;
				int64_t dist = get_dist(points[i], points[j]);
				if (dist < min_dist) {
					min_dist = dist;
					closest = j;
				}
			}
		}

		int64_t min_cost = 1LL << 60;
		for (int i = 0; i < 15; ++i) {
			int64_t cost = 0, vis = 0, all = (1LL << points.size()) - 1;
			vector<int> path;
			int p = prev_point, pi = -1;
			if (!points.empty() && points.front() == prev_point) {
				pi = 0;
				vis |= 1;
			}
			while (vis != all) {
				int next_index = -1, next = N + group;
				if (engine() % 2) {
					if (pi >= 0) {
						int next_candidate = closest_points[pi];
						if ((vis & (1LL << next_candidate)) == 0) {
							next_index = next_candidate;
							next = points[next_index];
						}
					}
				}
				while (p == next) {
					int next_candidate = engine() % points.size();
					if ((vis & (1LL << next_candidate)) == 0) {
						next_index = next_candidate;
						next = points[next_index];
					}
				}
				cost += get_dist(p, next);
				path.emplace_back(next);
				if (next_index >= 0) {
					vis |= (1LL << next_index);
				}
				pi = next_index;
				p = next;
			}
			cost += get_dist(path.empty() ? prev_point : path.back(), N + group);
			path.emplace_back(N + group);
			if (cost < min_cost) {
				min_cost = cost;
				r = path;
			}
		}
		return r;
	}

	vector<int> gen(const vector<int> &seq) {
		vector<int> r;
		r.emplace_back(0);
		for (int gg = 0; gg < M; ++gg) {
			vector<int> points;
			int target_group = seq[gg];
			for (int i = 0; i < N; ++i) {
				if (g[i] == target_group) {
					points.emplace_back(i);
				}
			}
			for (auto x : gen(r.back(), target_group, points)) {
				r.emplace_back(x);
			}
		}
		for (auto x : gen(r.back(), seq[0], {})) {
			r.emplace_back(x);
		}
		r.emplace_back(0);
		return r;
	}

	int64_t evaluate(const vector<int>& r) {
		int64_t s = 0;
		int prev = 0;
		for (int next : r) {
			s += get_dist(prev, next);
			prev = next;
		}
		return s;
	}

	void run() {
		int64_t min_score = 1LL << 60;
		vector<int> ans;

		while (!classify()) {
			;
		}

		vector<int> seq(M+1);
		iota(seq.begin(), seq.end(), 0);
		seq[M] = g[0];
		do {
			if (seq[0] == g[0]) {
				vector<int> r = gen(seq);
				int64_t score = evaluate(r);
				if (score < min_score) {
					min_score = score;
					ans = r;
				}
			}
		} while (next_permutation(seq.begin(), seq.begin() + M));

		output(ans);
	}
};

int main(int argc, char* argv[]) {
#if DEBUG
	freopen("in.txt", "r", stdin);
#endif
	Solver solver;
	solver.input();
	solver.prepare();
	solver.run();
}
0