結果

問題 No.5007 Steiner Space Travel
ユーザー takumi152takumi152
提出日時 2022-07-30 17:07:00
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 986 ms / 1,000 ms
コード長 16,139 bytes
コンパイル時間 3,673 ms
実行使用メモリ 6,952 KB
スコア 8,679,406
最終ジャッジ日時 2022-07-30 17:07:42
合計ジャッジ時間 35,981 ms
ジャッジサーバーID
(参考情報)
judge15 / judge11
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 986 ms
4,900 KB
testcase_01 AC 985 ms
4,900 KB
testcase_02 AC 985 ms
4,904 KB
testcase_03 AC 986 ms
4,904 KB
testcase_04 AC 985 ms
4,900 KB
testcase_05 AC 986 ms
4,904 KB
testcase_06 AC 985 ms
4,900 KB
testcase_07 AC 986 ms
4,904 KB
testcase_08 AC 986 ms
4,900 KB
testcase_09 AC 985 ms
4,900 KB
testcase_10 AC 986 ms
4,904 KB
testcase_11 AC 986 ms
4,904 KB
testcase_12 AC 985 ms
6,952 KB
testcase_13 AC 986 ms
4,900 KB
testcase_14 AC 985 ms
6,948 KB
testcase_15 AC 984 ms
4,900 KB
testcase_16 AC 986 ms
4,900 KB
testcase_17 AC 985 ms
4,904 KB
testcase_18 AC 985 ms
4,900 KB
testcase_19 AC 986 ms
6,952 KB
testcase_20 AC 985 ms
4,900 KB
testcase_21 AC 985 ms
6,952 KB
testcase_22 AC 986 ms
4,904 KB
testcase_23 AC 986 ms
4,904 KB
testcase_24 AC 986 ms
4,900 KB
testcase_25 AC 986 ms
4,900 KB
testcase_26 AC 985 ms
4,904 KB
testcase_27 AC 984 ms
4,908 KB
testcase_28 AC 986 ms
4,904 KB
testcase_29 AC 985 ms
4,904 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#pragma GCC optimize ("O3")
#pragma GCC optimize ("unroll-loops")
#pragma GCC target ("avx2")

#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <utility>
#include <string>
#include <queue>
#include <stack>
#include <unordered_set>
#include <random>
#include <cmath>
#include <cassert>

#include <x86intrin.h>

struct xorshift64 {
  unsigned long long int x = 88172645463325252ULL;
  inline unsigned short nextUShort() {
    x = x ^ (x << 7);
    return x = x ^ (x >> 9);
  }
  inline unsigned int nextUShortMod(unsigned long long int mod) {
    x = x ^ (x << 7);
    x = x ^ (x >> 9);
    return ((x & 0x0000ffffffffffff) * mod) >> 48;
  }
  inline unsigned int nextUInt() {
    x = x ^ (x << 7);
    return x = x ^ (x >> 9);
  }
  inline unsigned int nextUIntMod(unsigned long long int mod) {
    x = x ^ (x << 7);
    x = x ^ (x >> 9);
    return ((x & 0x00000000ffffffff) * mod) >> 32;
  }
  inline unsigned long long int nextULL() {
    x = x ^ (x << 7);
    return x = x ^ (x >> 9);
  }
  inline double nextDouble() {
    x = x ^ (x << 7);
    x = x ^ (x >> 9);
    return (double)x * 5.42101086242752217e-20;
  }
};

struct timer {
  double t = 0.0;
  double lastStop = 0.0;
  bool stopped = false;
  timer() {
    restart();
  }
  inline void restart() {
    t = now();
    stopped = false;
  }
  inline void start() {
    if (stopped) {
      t += now() - lastStop;
      stopped = false;
    }
  }
  inline void stop() {
    if (!stopped) {
      lastStop = now();
      stopped = true;
    }
  }
  inline double time() {
    if (stopped) return lastStop - t;
    else return now() - t;
  }
  inline double now() {
    unsigned long long l, h;
    __asm__ ("rdtsc" : "=a"(l), "=d"(h));
    #ifdef LOCAL
    return (double)(l | h << 32) * 2.857142857142857e-10; // 1 / 3.5e9, for local (Ryzen 9 3950X)
    #else
    // return (double)(l | h << 32) * 3.5714285714285715e-10; // 1 / 2.8e9, for AWS EC2 C3 (Xeon E5-2680 v2)
    // return (double)(l | h << 32) * 3.4482758620689656e-10; // 1 / 2.9e9, for AWS EC2 C4 (Xeon E5-2666 v3)
    // return (double)(l | h << 32) * 3.333333333333333e-10; // 1 / 3.0e9, for AWS EC2 C5 (Xeon Platinum 8124M / Xeon Platinum 8275CL)
    return (double)(l | h << 32) * 4.3478260869565215e-10; // 1 / 2.3e9, for yukicoder judge
    #endif
  }
};

using namespace std;

typedef long long int ll;
typedef unsigned long long int ull;
typedef pair<int, int> Pii;

const ll mod = 1000000007;

timer theTimer;
xorshift64 theRandom;
mt19937 theMersenne(1);

// hyper parameters

// enums

// structs

// constants
constexpr int planet_num = 100;
constexpr int station_num = 8;

constexpr int planet_cost_factor = 5;

// inputs
vector<Pii> planet_pos;

// outputs
vector<Pii> station_pos;
vector<Pii> route_info;

// internals
vector<vector<int> > planet_to_planet_cost;
vector<vector<int> > station_to_planet_cost;
vector<vector<int> > station_to_station_cost;

vector<int> planet_visit_order;

void receive_input() {
  int _n, _m;
  cin >> _n >> _m;
  planet_pos = vector<Pii>(planet_num);
  for (auto &planet: planet_pos) cin >> planet.first >> planet.second;
}

void init_planet_to_planet_cost() {
  planet_to_planet_cost = vector<vector<int> >(planet_num, vector<int>(planet_num));
  for (int i = 0; i < planet_num; i++) {
    for (int j = i; j < planet_num; j++) {
      planet_to_planet_cost[i][j] = planet_cost_factor * planet_cost_factor * ((planet_pos[i].first - planet_pos[j].first) * (planet_pos[i].first - planet_pos[j].first) + (planet_pos[i].second - planet_pos[j].second) * (planet_pos[i].second - planet_pos[j].second));
      planet_to_planet_cost[j][i] = planet_to_planet_cost[i][j];
    }
  }
}

void init_station_to_planet_cost() {
  station_to_planet_cost = vector<vector<int> >(station_num, vector<int>(planet_num));
  for (int i = 0; i < station_num; i++) {
    for (int j = 0; j < planet_num; j++) {
      station_to_planet_cost[i][j] = planet_cost_factor * ((station_pos[i].first - planet_pos[j].first) * (station_pos[i].first - planet_pos[j].first) + (station_pos[i].second - planet_pos[j].second) * (station_pos[i].second - planet_pos[j].second));
    }
  }
}

void init_station_to_station_cost() {
  station_to_station_cost = vector<vector<int> >(station_num, vector<int>(planet_num));
  for (int i = 0; i < station_num; i++) {
    for (int j = i; j < station_num; j++) {
      station_to_station_cost[i][j] = ((station_pos[i].first - station_pos[j].first) * (station_pos[i].first - station_pos[j].first) + (station_pos[i].second - station_pos[j].second) * (station_pos[i].second - station_pos[j].second));
      station_to_station_cost[j][i] = station_to_station_cost[i][j];
    }
  }
}

void init() {
  station_pos = vector<Pii>(station_num);
  for (int i = 0; i < station_num; i++) {
    station_pos[i] = Pii(theRandom.nextUIntMod(801) + 100, theRandom.nextUIntMod(801) + 100);
  }
  {
    vector<int> planet_cluster(planet_num);
    for (int i = 0; i < planet_num; i++) planet_cluster[i] = theRandom.nextUIntMod(station_num);
    vector<int> next_planet_cluster = planet_cluster;
    int iter_count = 0;
    do {
      planet_cluster = next_planet_cluster;
      vector<int> cluster_count(station_num);
      vector<Pii> cluster_pos_sum(station_num);
      for (int i = 0; i < planet_num; i++) {
        cluster_count[planet_cluster[i]]++;
        cluster_pos_sum[planet_cluster[i]].first += planet_pos[i].first;
        cluster_pos_sum[planet_cluster[i]].second += planet_pos[i].second;
      }
      for (int i = 0; i < station_num; i++) {
        if (cluster_count[i] > 0) {
          station_pos[i] = Pii(cluster_pos_sum[i].first / cluster_count[i], cluster_pos_sum[i].second / cluster_count[i]);
        }
      }
      for (int i = 0; i < planet_num; i++) {
        int nearest_station = -1;
        int nearest_distance = 1000000007;
        for (int j = 0; j < station_num; j++) {
          int dist = (planet_pos[i].first - station_pos[j].first) * (planet_pos[i].first - station_pos[j].first) + (planet_pos[i].second - station_pos[j].second) * (planet_pos[i].second - station_pos[j].second);
          if (dist < nearest_distance) {
            nearest_station = j;
            nearest_distance = dist;
          }
        }
        next_planet_cluster[i] = nearest_station;
      }
      iter_count++;
    } while (planet_cluster != next_planet_cluster || iter_count < 100);
  }

  init_planet_to_planet_cost();
  init_station_to_planet_cost();
  init_station_to_station_cost();

  planet_visit_order = vector<int>(planet_num + 1);
  {
    planet_visit_order[0] = 0;
    planet_visit_order[planet_num] = 0;
    int current_planet = 0;
    vector<bool> visited(planet_num);
    visited[0] = true;
    for (int i = 1; i < planet_num; i++) {
      int best_planet = -1;
      int best_cost = 1000000007;
      for (int j = 0; j < planet_num; j++) {
        if (!visited[j] && planet_to_planet_cost[current_planet][j] < best_cost) {
          best_planet = j;
          best_cost = planet_to_planet_cost[current_planet][j];
        }
      }
      planet_visit_order[i] = best_planet;
      current_planet = best_planet;
      visited[best_planet] = true;
    }
  }
}

vector<Pii> find_shortest_route(int planet_from, int planet_to) {
  vector<bool> planet_visited(planet_num);
  vector<bool> station_visited(station_num);
  vector<Pii> planet_prev_entity(planet_num);
  vector<Pii> station_prev_entity(station_num);
  priority_queue<tuple<int, int, int, int, int>, vector<tuple<int, int, int, int, int> >, greater<tuple<int, int, int, int, int> > > que; // cost, entity_type, entity_id, prev_entity_type, prev_entity_id
  que.emplace(0, 1, planet_from, 1, planet_from);
  while (!que.empty()) {
    auto [cost, entity_type, entity_id, prev_entity_type, prev_entity_id] = que.top();
    que.pop();
    if (entity_type == 1) { // planet
      if (planet_visited[entity_id]) continue;
      planet_visited[entity_id] = true;
      planet_prev_entity[entity_id] = Pii(prev_entity_type, prev_entity_id);
      if (entity_id == planet_to) {
        cerr << setw(4) << planet_pos[planet_from].first << " " << setw(4) << planet_pos[planet_from].second << " " << setw(4) << planet_pos[planet_to].first << " " << setw(4) << planet_pos[planet_to].second << " " << setw(6) << cost << endl;
        break;
      }
      for (int next_planet = 0; next_planet < planet_num; next_planet++) {
        if (!planet_visited[next_planet]) {
          que.emplace(cost + planet_to_planet_cost[entity_id][next_planet], 1, next_planet, entity_type, entity_id);
        }
      }
      for (int next_station = 0; next_station < station_num; next_station++) {
        if (!station_visited[next_station]) {
          que.emplace(cost + station_to_planet_cost[next_station][entity_id], 2, next_station, entity_type, entity_id);
        }
      }
    }
    else if (entity_type == 2) { // station
      if (station_visited[entity_id]) continue;
      station_visited[entity_id] = true;
      station_prev_entity[entity_id] = Pii(prev_entity_type, prev_entity_id);
      for (int next_planet = 0; next_planet < planet_num; next_planet++) {
        if (!planet_visited[next_planet]) {
          que.emplace(cost + station_to_planet_cost[entity_id][next_planet], 1, next_planet, entity_type, entity_id);
        }
      }
      for (int next_station = 0; next_station < station_num; next_station++) {
        if (!station_visited[next_station]) {
          que.emplace(cost + station_to_station_cost[entity_id][next_station], 2, next_station, entity_type, entity_id);
        }
      }
    }
  }

  vector<Pii> route;
  int current_entity_type = 1;
  int current_entity_id = planet_to;
  while (!(current_entity_type == 1 && current_entity_id == planet_from)) {
    route.emplace_back(current_entity_type, current_entity_id);
    if (current_entity_type == 1) { // planet
      auto [prev_entity_type, prev_entity_id] = planet_prev_entity[current_entity_id];
      current_entity_type = prev_entity_type;
      current_entity_id = prev_entity_id;
    }
    else if (current_entity_type == 2) { // station
      auto [prev_entity_type, prev_entity_id] = station_prev_entity[current_entity_id];
      current_entity_type = prev_entity_type;
      current_entity_id = prev_entity_id;
    }
  }
  reverse(route.begin(), route.end());
  return route;
}

void update_route_info() {
  route_info.emplace_back(1, 0);
  for (int i = 0; i < planet_num; i++) {
    auto path = find_shortest_route(planet_visit_order[i], planet_visit_order[i + 1]);
    for (auto &entity: path) route_info.push_back(entity);
  }
}

void solve() {
  vector<vector<int> > planet_to_planet_path_cost(planet_num, vector<int>(planet_num));
  {
    for (int i = 0; i < planet_num; i++) {
      for (int j = 0; j < planet_num; j++) {
        planet_to_planet_path_cost[i][j] = planet_to_planet_cost[i][j];
      }
    }
    for (int k = 0; k < planet_num; k++) {
      for (int i = 0; i < planet_num; i++) {
        for (int j = 0; j < planet_num; j++) {
          if (planet_to_planet_path_cost[i][k] + planet_to_planet_path_cost[k][j] < planet_to_planet_path_cost[i][j]) planet_to_planet_path_cost[i][j] = planet_to_planet_path_cost[i][k] + planet_to_planet_path_cost[k][j];
        }
      }
    }
  }
  vector<vector<int> > cost_from_to(planet_num + station_num, vector<int>(planet_num + station_num));
  auto update_cost = [&]() {
    for (int i = 0; i < planet_num + station_num; i++) {
      for (int j = 0; j < planet_num + station_num; j++) {
        if (i < planet_num && j < planet_num) cost_from_to[i][j] = planet_to_planet_path_cost[i][j];
        else if (i < planet_num)              cost_from_to[i][j] = station_to_planet_cost[j - planet_num][i];
        else if (j < planet_num)              cost_from_to[i][j] = station_to_planet_cost[i - planet_num][j];
        else                                  cost_from_to[i][j] = station_to_station_cost[i - planet_num][j - planet_num];
      }
    }
    for (int k = planet_num; k < planet_num + station_num; k++) {
      for (int i = 0; i < planet_num + station_num; i++) {
        for (int j = 0; j < planet_num + station_num; j++) {
          if (cost_from_to[i][k] + cost_from_to[k][j] < cost_from_to[i][j]) cost_from_to[i][j] = cost_from_to[i][k] + cost_from_to[k][j];
        }
      }
    }
  };
  update_cost();

  {
    auto calc_score = [&]() {
      int score = 0;
      for (int i = 0; i < planet_num; i++) score += cost_from_to[planet_visit_order[i]][planet_visit_order[i+1]];
      return score;
    };

    int score = calc_score();
    int last_score = score;
    int best_score = score;

    const double base_temperature = 3e3;
    const double target_temperature = 1e2;
    // const double decay_rate = 4e-5;
    double temperature = base_temperature;

    double time_start = theTimer.time();
    const double time_limit = 0.980;
    int iter_count = 0;

    while (theTimer.time() < time_limit) {
      double roll = theRandom.nextDouble();
      if (roll < 0.90) {
        int p1 = theRandom.nextUIntMod(planet_num - 1) + 1;
        int p2 = theRandom.nextUIntMod(planet_num - 1) + 1;
        if (p1 == p2) continue;

        swap(planet_visit_order[p1], planet_visit_order[p2]);

        score = calc_score();

        #ifdef DEBUG
        if (iter_count % 1000 == 0) cerr << iter_count << " " << score << " " << last_score << " " << best_score << " " << temperature << " " << theTimer.time() << endl;
        #endif

        if (score <= last_score) {
          last_score = score;
          if (score < best_score) {
            best_score = score;
          }
        }
        else if (theRandom.nextDouble() < exp(double(last_score - score) / temperature)) { // accept
          last_score = score;
        }
        else { // rollback
          swap(planet_visit_order[p1], planet_visit_order[p2]);
          score = last_score;
        }
      }
      else if (roll < 1.00) {
        int s = theRandom.nextUIntMod(station_num);
        int dx = theRandom.nextUIntMod(201) - 100;
        int dy = theRandom.nextUIntMod(201) - 100;
        if (dx == 0 && dy == 0) continue;
        if (!(0 <= station_pos[s].first + dx && station_pos[s].first + dx <= 1000) || !(0 <= station_pos[s].second + dy && station_pos[s].second + dy <= 1000)) continue;

        station_pos[s].first += dx;
        station_pos[s].second += dy;
        init_station_to_planet_cost();
        init_station_to_station_cost();
        update_cost();

        score = calc_score();

        #ifdef DEBUG
        if (iter_count % 1000 == 0) cerr << iter_count << " " << score << " " << last_score << " " << best_score << " " << temperature << " " << theTimer.time() << endl;
        #endif

        if (score <= last_score) {
          last_score = score;
          if (score < best_score) {
            best_score = score;
          }
        }
        else if (theRandom.nextDouble() < exp(double(last_score - score) / temperature)) { // accept
          last_score = score;
        }
        else { // rollback
          station_pos[s].first -= dx;
          station_pos[s].second -= dy;
          init_station_to_planet_cost();
          init_station_to_station_cost();
          update_cost();
          score = last_score;
        }
      }

      // temperature *= 1.0 - decay_rate;
      temperature = exp(log(base_temperature) - ((log(base_temperature) - log(target_temperature)) * ((theTimer.time() - time_start) * (1.0 / (time_limit - time_start)))));
      iter_count++;
    }

    cerr << "iter_count   = " << iter_count << endl;
    cerr << "score        = " << score << endl;
    cerr << "best_score   = " << best_score << endl;
    cerr << "temperature  = " << temperature << endl;
  }

  update_route_info();
}

void output_ans() {
  for (auto &station: station_pos) {
    cout << station.first << " " << station.second << endl;
  }
  cout << route_info.size() << endl;
  for (auto &route: route_info) {
    cout << route.first << " " << route.second + 1 << endl;
  }
}

int main(int argc, char *argv[]) {
  cin.tie(0);
  ios::sync_with_stdio(false);

  receive_input();

  init();
  solve();

  output_ans();

  return 0;
}
0