結果
| 問題 |
No.5007 Steiner Space Travel
|
| コンテスト | |
| ユーザー |
t33f
|
| 提出日時 | 2022-07-30 15:35:31 |
| 言語 | C++17(gcc12) (gcc 12.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 982 ms / 1,000 ms |
| コード長 | 5,560 bytes |
| コンパイル時間 | 1,335 ms |
| 実行使用メモリ | 6,956 KB |
| スコア | 8,353,513 |
| 最終ジャッジ日時 | 2022-07-30 15:36:05 |
| 合計ジャッジ時間 | 33,577 ms |
|
ジャッジサーバーID (参考情報) |
judge15 / judge11 |
| 純コード判定しない問題か言語 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 30 |
ソースコード
#include <cmath>
#include <map>
#include <array>
#include <algorithm>
#include <chrono>
#include <random>
#include <vector>
#include <numeric>
#include <cassert>
#include <iostream>
using namespace std;
class Timer {
chrono::system_clock::time_point start_time = chrono::system_clock::now();
public:
Timer() {}
long long get_elapsed_time() {
auto diff = chrono::system_clock::now() - start_time;
return chrono::duration_cast<chrono::milliseconds>(diff).count();
}
};
using P = pair<int, int>;
constexpr int N = 100, M = 8;
int a[N], b[N];
void read_input() {
{
int n, m;
cin >> n >> m;
assert(n == N);
assert(m == M);
}
for (int i = 0; i < N; i++) cin >> a[i] >> b[i];
}
mt19937 mt;
constexpr int alpha = 5;
int L22(int x1, int y1, int x2, int y2) {
const int dx = x1 - x2, dy = y1 - y2;
return dx * dx + dy * dy;
}
int L22(P p, P q) { return L22(p.first, p.second, q.first, q.second); }
int cost(int i, int j) {
return L22(a[i], b[i], a[j], b[j]) * alpha * alpha;
}
int cost(int i, int j, P middle) {
return (L22(a[i], b[i], middle.first, middle.second) +
L22(a[j], b[j], middle.first, middle.second)) * alpha;
}
int cost(int t1, P p1, int t2, P p2) {
const int coeff = (t1 == 1 && t2 == 1 ? alpha * alpha :
t1 == 1 || t2 == 1 ? alpha :
1);
return coeff * L22(p1, p2);
}
vector<int> solve_tsp(int tl) {
vector<int> ans(N);
iota(ans.begin(), ans.end(), 0);
int total_cost = 0;
for (int i = 0; i < N; i++) {
if (i + 1 < N) total_cost += cost(i, i + 1);
else total_cost += cost(0, N - 1);
}
Timer timer;
uniform_int_distribution<int> randindex(0, N - 1);
int iter = 0;
while (timer.get_elapsed_time() < tl) {
int i = randindex(mt), j = randindex(mt);
assert(i < N);
assert(j < N);
if (i == j) continue;
if (i > j) swap(i, j);
if (i + 1 == j) continue;
iter++;
const int k = (j + 1 == N ? 0 : j + 1);
const int diff = (cost(ans[i], ans[j]) + cost(ans[i + 1], ans[k])
- cost(ans[i], ans[i + 1]) - cost(ans[j], ans[k]));
if (diff <= 0) {
reverse(ans.begin() + i + 1, ans.begin() + j + 1);
total_cost += diff;
// cerr << iter << ' ' << total_cost << endl;
}
}
cerr << iter << ' ' << total_cost << endl;
return ans;
}
class DSU {
vector<int> par, rank;
public:
explicit DSU(int n) : par(n), rank(n, 0) {
iota(par.begin(), par.end(), 0);
}
int find(int i) {
return (par[i] == i) ? i : (par[i] = find(par[i]));
}
void merge(int i, int j) {
int x = find(i), y = find(j);
if (x != y) {
if (rank[x] < rank[y])
par[x] = y;
else {
par[y] = x;
if (rank[x] == rank[y]) rank[x]++;
}
}
}
bool same(int i, int j) { return find(i) == find(j); }
};
struct Target {
int type, idx;
Target(int type, int idx) : type(type), idx(idx) {
assert(type == 1 || type == 2);
}
};
struct Config {
vector<int> path;
array<P, M> stations;
};
pair<vector<Target>, long long> greedy(const Config &conf) {
vector<Target> ans;
for (int i = 0; i < N; i++) {
int cur_cost = cost(conf.path[i], conf.path[i + 1]), s = -1;
for (int j = 0; j < M; j++) {
const int tmp = cost(conf.path[i], conf.path[i + 1], conf.stations[j]);
if (tmp < cur_cost) {
cur_cost = tmp;
s = j;
}
}
ans.emplace_back(1, conf.path[i]);
if (s >= 0) {
ans.emplace_back(2, s);
}
}
ans.emplace_back(1, 0);
long long total_cost = 0;
for (size_t i = 0; i + 1 < ans.size(); i++) {
const auto [t1, i1] = ans[i];
const auto [t2, i2] = ans[i + 1];
const P p1 = (t1 == 1 ? make_pair(a[i1], b[i1]) : conf.stations[i1]),
p2 = (t2 == 1 ? make_pair(a[i2], b[i2]) : conf.stations[i2]);
total_cost += cost(t1, p1, t2, p2);
}
return {ans, total_cost};
}
int main() {
read_input();
vector<int> path = solve_tsp(100);
{
auto start = find(path.begin(), path.end(), 0);
assert(start != path.end());
rotate(path.begin(), start, path.end());
assert(path.front() == 0);
path.push_back(0);
}
array<P, M> stations{
P{200, 333}, {200, 667},
{400, 333}, {400, 667},
{600, 333}, {600, 667},
{800, 333}, {800, 667},
};
auto [ans, cur_cost] = greedy({path, stations});
Timer timer;
int iter = 0;
uniform_int_distribution<int> rand_pos(10, 990);
while (timer.get_elapsed_time() < 880) {
iter++;
const int i = iter % M;
const P origp = stations[i],
newp = P(rand_pos(mt), rand_pos(mt));
stations[i] = newp;
const auto [tmp_ans, tmp_cost] = greedy({path, stations});
if (tmp_cost < cur_cost) {
cur_cost = tmp_cost;
ans = tmp_ans;
cerr << cur_cost << ' ' << round(1e9 / (1000 + sqrt(cur_cost))) << endl;
} else {
// rollback
stations[i] = origp;
}
}
// output
for (auto [x, y] : stations) cout << x << ' ' << y << '\n';
cout << ans.size() << '\n';
for (auto [t, i] : ans) cout << t << ' ' << i + 1 << '\n';
}
t33f