結果
| 問題 |
No.5007 Steiner Space Travel
|
| コンテスト | |
| ユーザー |
t33f
|
| 提出日時 | 2022-07-30 16:45:23 |
| 言語 | C++17(gcc12) (gcc 12.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 982 ms / 1,000 ms |
| コード長 | 7,854 bytes |
| コンパイル時間 | 1,342 ms |
| 実行使用メモリ | 6,952 KB |
| スコア | 8,405,705 |
| 最終ジャッジ日時 | 2022-07-30 16:45:57 |
| 合計ジャッジ時間 | 33,540 ms |
|
ジャッジサーバーID (参考情報) |
judge13 / judge15 |
| 純コード判定しない問題か言語 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| 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;
unsigned int xor128() {
static unsigned int x=123456789, y=362436069, z=521288629, w=88675123;
unsigned int t;
t=(x^(x<<11)); x=y; y=z; z=w;
return (w=(w^(w>>19))^(t^(t>>8)));
}
inline bool rand_bool(double prob) {
constexpr double x = 1LL<<32; // uint_max+1
return xor128() < prob * x;
}
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();
}
} timer;
using P = pair<int, int>;
constexpr int N = 100, M = 8;
int a[N], b[N];
mt19937 mt;
constexpr int alpha = 5;
int L1(P p, P q) { return abs(p.first - q.first) + abs(p.second - q.second); }
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);
}
array<array<int, N>, N> mincost;
array<array<int, N>, N> next_idx;
void calc_mincost() {
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++) {
mincost[i][j] = cost(i, j);
next_idx[i][j] = j;
}
for (int k = 0; k < N; k++)
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
if (mincost[i][k] + mincost[k][j] < mincost[i][j]) {
mincost[i][j] = mincost[i][k] + mincost[k][j];
assert(i != k);
assert(j != k);
next_idx[i][j] = next_idx[i][k];
}
}
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];
calc_mincost();
}
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 tsp_timer;
uniform_int_distribution<int> randindex(0, N - 1);
int iter = 0, last_upd = 0, stop_threshold = N * N;
while (tsp_timer.get_elapsed_time() < tl && last_upd + stop_threshold > iter) {
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;
last_upd = iter;
// 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;
ans.emplace_back(1, conf.path[0]);
long long total_cost = 0;
for (int i = 0; i < N; i++) {
const int from = conf.path[i], to = conf.path[i + 1];
int cur_cost = mincost[from][to], s = -1;
for (int j = 0; j < M; j++) {
const int tmp = cost(from, to, conf.stations[j]);
if (tmp < cur_cost) {
cur_cost = tmp;
s = j;
}
}
if (s >= 0) {
const auto [t1, i1] = ans.back();
assert(t1 == 1);
total_cost += cost(1, make_pair(a[i1], b[i1]), 2, conf.stations[s]);
ans.emplace_back(2, s);
total_cost += cost(2, conf.stations[s], 1, make_pair(a[to], b[to]));
ans.emplace_back(1, to);
} else {
for (int cur = from; cur != to; cur = next_idx[cur][to]) {
const auto [t1, i1] = ans.back();
assert(t1 == 1);
assert(i1 == cur);
const int nxt = next_idx[cur][to];
total_cost += cost(1, make_pair(a[cur], b[cur]), 1, make_pair(a[nxt], b[nxt]));
ans.emplace_back(1, nxt);
}
}
}
return {ans, total_cost};
}
int timelimit = 1000, margin = 20;
int main() {
read_input();
vector<int> path = solve_tsp(200);
{
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 [cur_ans, cur_cost] = greedy({path, stations});
vector<Target> best_ans = cur_ans;
long long best_cost = cur_cost;
int iter = 0;
uniform_int_distribution<int> rand_pos(10, 990);
while (timer.get_elapsed_time() + margin < timelimit) {
iter++;
const int i = iter % M;
const P origp = stations[i],
newp(rand_pos(mt), rand_pos(mt));
stations[i] = newp;
const auto [tmp_ans, tmp_cost] = greedy({path, stations});
if (tmp_cost < best_cost) {
cerr << iter << ' ' << tmp_cost << ' ' << round(1e9 / (1000 + sqrt(tmp_cost))) << endl;
best_cost = tmp_cost;
best_ans = tmp_ans;
}
const long long diff = tmp_cost - cur_cost;
bool accept = diff <= 0;
// if (!accept) {
// const double start_temp = 2e4, end_temp = 1,
// progress = double(timer.get_elapsed_time()) / timelimit,
// temp = start_temp + (end_temp - start_temp) * progress,
// prob = exp(-diff / temp);
// accept = rand_bool(prob);
// // cerr << diff << ' ' << prob << endl;
// }
if (accept) {
cur_cost = tmp_cost;
cur_ans = tmp_ans;
} else {
// rollback
stations[i] = origp;
}
}
cerr << iter << ' ' << round(1e9 / (1000 + sqrt(best_cost))) << endl;
// output
for (auto [x, y] : stations) cout << x << ' ' << y << '\n';
cout << best_ans.size() << '\n';
for (auto [t, i] : best_ans) cout << t << ' ' << i + 1 << '\n';
}
t33f