結果

問題 No.5023 Airlines Optimization
コンテスト
ユーザー Shymohn _
提出日時 2026-02-25 22:20:14
言語 C++23
(gcc 15.2.0 + boost 1.89.0)
コンパイル:
g++-15 -O2 -lm -std=c++23 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
AC  
実行時間 957 ms / 1,000 ms
コード長 15,231 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 5,401 ms
コンパイル使用メモリ 371,860 KB
実行使用メモリ 7,848 KB
スコア 36,458,602
最終ジャッジ日時 2026-02-25 22:22:07
合計ジャッジ時間 106,771 ms
ジャッジサーバーID
(参考情報)
judge6 / judge2
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 100
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#include <bits/stdc++.h>
using namespace std;
# pragma GCC target("avx2")
# pragma GCC optimize("O3")
# pragma GCC optimize("unroll-loops")


/*
  修正版 Main.cpp
  - 警告・エラー修正済み (std::move, 重複定義削除, 未使用変数削除)
  - 挙動は以前提示した焼きなまし + 近傍操作の実装と同じ
*/

struct City { double x, y; long long w; };
struct Flight { int a; int dep; int b; int arr; }; // dep/arr in minutes from midnight

int travel_time_minutes(double x1, double y1, double x2, double y2) {
    double d = hypot(x1 - x2, y1 - y2);
    double raw = 60.0 * d / 800.0 + 40.0;
    int tt = (int)ceil(raw / 5.0) * 5;
    return tt;
}

string fmt_time(int t){
    int hh = t / 60;
    int mm = t % 60;
    char buf[6];
    sprintf(buf, "%02d:%02d", hh, mm);
    return string(buf);
}

const int START = 6*60;   // 360
const int END   = 21*60;  // 1260
const int INF_NEG = -1000000000;

// Convert "HH:MM" to minutes
int parse_time(const string &s){
    int hh = stoi(s.substr(0,2));
    int mm = stoi(s.substr(3,2));
    return hh*60 + mm;
}

using Schedule = vector<vector<Flight>>;

// Build list of target arrival times: 11:00..21:00 step 30
vector<int> build_target_times() {
    vector<int> T;
    for (int t = 11*60; t <= 21*60; t += 30) T.push_back(t);
    return T;
}

// Flatten schedules into flight vector
vector<Flight> flatten_schedule(const Schedule &schedules) {
    vector<Flight> flights;
    for (const auto &sch : schedules) {
        for (const auto &f : sch) flights.push_back(f);
    }
    return flights;
}

// compute flights_by_arrival mapping for given flights
vector<vector<int>> build_flights_by_arrival(const vector<Flight> &flights, int N) {
    vector<vector<int>> fba(N);
    for (int i = 0; i < (int)flights.size(); ++i) {
        int arr_city = flights[i].b;
        fba[arr_city].push_back(i);
    }
    return fba;
}

// Given flights (list) and flights_by_arrival, compute for all dest and all target times T the latest departure times
// returns res[dest][t_idx][city] = latest departure time from city to reach dest by T (or INF_NEG)
vector<vector<vector<int>>> compute_latest_deps_all(int N, const vector<Flight> &flights, const vector<vector<int>> &fba, const vector<int> &Tlist) {
    int D = N;
    int TT = (int)Tlist.size();
    vector<vector<vector<int>>> res(D, vector<vector<int>>(TT, vector<int>(N, INF_NEG)));
    // For each dest and target time, do reverse BFS/DP
    for (int dest = 0; dest < D; ++dest) {
        for (int ti = 0; ti < TT; ++ti) {
            int T = Tlist[ti];
            vector<int> L(N, INF_NEG);
            deque<int> dq;
            L[dest] = T;
            dq.push_back(dest);
            while (!dq.empty()) {
                int v = dq.front(); dq.pop_front();
                // all flights that arrive at v
                for (int fi : fba[v]) {
                    const Flight &f = flights[fi];
                    if (f.arr <= L[v]) {
                        int u = f.a;
                        if (L[u] < f.dep) {
                            L[u] = f.dep;
                            dq.push_back(u);
                        }
                    }
                }
            }
            res[dest][ti] = std::move(L);
        }
    }
    return res;
}

// compute latest_deps for circle (s_ci) given current schedules: returns res[dest][ti][city]
vector<vector<vector<int>>> compute_s_ci_all(const Schedule &schedules, const vector<City> &cities, const vector<int> &Tlist) {
    // flatten flights with indices, build flights_by_arrival
    vector<Flight> flights = flatten_schedule(schedules);
    int N = (int)cities.size();
    vector<vector<int>> fba = build_flights_by_arrival(flights, N);
    // compute latest deps
    return compute_latest_deps_all(N, flights, fba, Tlist);
}

// Evaluate share-rate S given precomputed s_sq for Square and computed s_ci for Circle
long double compute_share_rate(const vector<vector<vector<int>>> &s_sq_all, const vector<vector<vector<int>>> &s_ci_all,
                               const vector<pair<int,int>> &ODlist, const vector<int> &Tlist,
                               const vector<City> &cities) {
    long double v_ci = 0.0L, v_sq = 0.0L;
    int TT = (int)Tlist.size();
    for (auto &od : ODlist) {
        int u = od.first;
        int v = od.second;
        long long weight = cities[u].w * cities[v].w;
        for (int ti = 0; ti < TT; ++ti) {
            int s_sq = s_sq_all[v][ti][u];
            int s_ci = s_ci_all[v][ti][u];
            if (s_sq < s_ci) v_ci += (long double)weight;
            else v_sq += (long double)weight;
        }
    }
    if (v_ci + v_sq <= 0.0L) return 0.0L;
    return v_ci / (v_ci + v_sq);
}

// Build initial schedule as hub <-> top25 (or up to available) round-robin
Schedule build_initial(const vector<City> &cities, int K) {
    int N = cities.size();
    // find hub
    int hub = 0;
    for (int i = 1; i < N; ++i) if (cities[i].w > cities[hub].w) hub = i;
    // sort others by pop
    vector<pair<long long,int>> vec;
    for (int i = 0; i < N; ++i) if (i != hub) vec.emplace_back(cities[i].w, i);
    sort(vec.begin(), vec.end(), [](const auto &A, const auto &B){
        if (A.first != B.first) return A.first > B.first;
        return A.second < B.second;
    });
    int needSpokes = 25;
    int topCount = min((int)vec.size(), needSpokes);
    vector<int> targets;
    for (int i = 0; i < topCount; ++i) targets.push_back(vec[i].second);

    Schedule schedules(K);
    if (topCount == 0) return schedules;

    for (int k = 0; k < K; ++k) {
        int target = targets[k % topCount];
        int cur = hub;
        int time = START;
        while (true) {
            int next = (cur == hub) ? target : hub;
            int tt = travel_time_minutes(cities[cur].x, cities[cur].y, cities[next].x, cities[next].y);
            int dep = time;
            int arr = dep + tt;
            if (arr > END) break;
            schedules[k].push_back({cur, dep, next, arr});
            cur = next;
            time = arr;
        }
    }
    return schedules;
}

// Greedy extend from (cur, time) for a single plane
vector<Flight> greedy_extend_from(const vector<City> &cities, int cur, int time) {
    vector<Flight> res;
    int N = cities.size();
    while (true) {
        int best = -1, best_tt = INT_MAX;
        for (int j = 0; j < N; ++j) {
            if (j == cur) continue;
            int tt = travel_time_minutes(cities[cur].x, cities[cur].y, cities[j].x, cities[j].y);
            if (time + tt > END) continue;
            if (tt < best_tt || (tt == best_tt && j < best)) {
                best_tt = tt; best = j;
            }
        }
        if (best == -1) break;
        int dep = time;
        int arr = dep + best_tt;
        res.push_back({cur, dep, best, arr});
        cur = best;
        time = arr;
    }
    return res;
}

// Attempt neighbor operations on schedules (modify only one plane's schedule minimally).
// Returns pair<bool,int> : whether changed, and index of plane changed
pair<bool,int> apply_random_neighbor(Schedule &schedules, const vector<City> &cities, mt19937_64 &rng) {
    int K = schedules.size();
    uniform_int_distribution<int> pick_plane(0, max(0, K-1));
    int k = pick_plane(rng);
    vector<Flight> &sch = schedules[k];
    int n = sch.size();
    uniform_int_distribution<int> opdist(0,1);
    int op = opdist(rng);
    if (n == 0) {
        int hub = 0;
        for (int i = 1; i < (int)cities.size(); ++i) if (cities[i].w > cities[hub].w) hub = i;
        vector<Flight> newsch = greedy_extend_from(cities, hub, START);
        if (!newsch.empty()) {
            sch = std::move(newsch);
            return {true, k};
        } else return {false, -1};
    }
    vector<Flight> backup = sch;
    if (op == 0) {
        // change destination of random flight p
        uniform_int_distribution<int> pick_pos(0, n-1);
        int p = pick_pos(rng);
        int cur; int time;
        if (p == 0) { cur = sch[0].a; time = sch[0].dep; }
        else { cur = sch[p-1].b; time = sch[p-1].arr; }
        vector<int> cand;
        int N = cities.size();
        for (int j = 0; j < N; ++j) {
            if (j == cur) continue;
            int tt = travel_time_minutes(cities[cur].x, cities[cur].y, cities[j].x, cities[j].y);
            if (time + tt <= END) cand.push_back(j);
        }
        if (cand.empty()) return {false, -1};
        int cur_b = sch[p].b;
        vector<int> cand2;
        for (int v : cand) if (v != cur_b) cand2.push_back(v);
        if (cand2.empty()) return {false, -1};
        uniform_int_distribution<int> pick_cand(0, (int)cand2.size()-1);
        int newdest = cand2[pick_cand(rng)];
        sch.erase(sch.begin() + p, sch.end());
        int tt = travel_time_minutes(cities[cur].x, cities[cur].y, cities[newdest].x, cities[newdest].y);
        int dep = time;
        int arr = dep + tt;
        sch.push_back({cur, dep, newdest, arr});
        int cur_city = newdest;
        int cur_time = arr;
        // attempt to preserve suffix from backup where possible
        for (int j = p+1; j < (int)backup.size(); ++j) {
            const Flight &orig = backup[j];
            int required_tt = travel_time_minutes(cities[orig.a].x, cities[orig.a].y, cities[orig.b].x, cities[orig.b].y);
            if (orig.a == cur_city && orig.dep >= cur_time && orig.arr - orig.dep == required_tt) {
                sch.push_back(orig);
                cur_city = orig.b;
                cur_time = orig.arr;
            } else {
                vector<Flight> tail = greedy_extend_from(cities, cur_city, cur_time);
                sch.insert(sch.end(), tail.begin(), tail.end());
                break;
            }
        }
        return {true, k};
    } else {
        // shift departure of random flight p by +/-5
        uniform_int_distribution<int> pick_pos(0, n-1);
        int p = pick_pos(rng);
        int prev_arr = (p==0) ? START : sch[p-1].arr;
        int dep = sch[p].dep;
        int tt = sch[p].arr - sch[p].dep;
        vector<int> cand_dep;
        if (dep - 5 >= prev_arr) cand_dep.push_back(dep - 5);
        if (dep + 5 + tt <= END) cand_dep.push_back(dep + 5);
        if (cand_dep.empty()) return {false, -1};
        uniform_int_distribution<int> pickd(0, (int)cand_dep.size()-1);
        int new_dep = cand_dep[pickd(rng)];
        int new_arr = new_dep + tt;
        int a_orig = sch[p].a;
        int b_orig = sch[p].b;
        sch.erase(sch.begin() + p, sch.end());
        sch.push_back({a_orig, new_dep, b_orig, new_arr});
        int cur_city = b_orig;
        int cur_time = new_arr;
        for (int j = p+1; j < (int)backup.size(); ++j) {
            const Flight &orig = backup[j];
            int required_tt = travel_time_minutes(cities[orig.a].x, cities[orig.a].y, cities[orig.b].x, cities[orig.b].y);
            if (orig.a == cur_city && orig.dep >= cur_time && orig.arr - orig.dep == required_tt) {
                sch.push_back(orig);
                cur_city = orig.b;
                cur_time = orig.arr;
            } else {
                vector<Flight> tail = greedy_extend_from(cities, cur_city, cur_time);
                sch.insert(sch.end(), tail.begin(), tail.end());
                break;
            }
        }
        return {true, k};
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int N; int R;
    if (!(cin >> N >> R)) return 0;
    vector<City> cities(N);
    for (int i = 0; i < N; ++i) {
        long long xi, yi, wi;
        cin >> xi >> yi >> wi;
        cities[i].x = (double)xi;
        cities[i].y = (double)yi;
        cities[i].w = wi;
    }
    int M; cin >> M;
    vector<Flight> square_flights;
    square_flights.reserve(M);
    for (int i = 0; i < M; ++i) {
        int a, b; string s_str, t_str;
        cin >> a >> s_str >> b >> t_str;
        int smin = parse_time(s_str);
        int tmin = parse_time(t_str);
        square_flights.push_back({a-1, smin, b-1, tmin});
    }
    int K; cin >> K;

    // Precompute Tlist and ODlist (pairs with distance >= 0.25R)
    vector<int> Tlist = build_target_times();
    vector<pair<int,int>> ODlist;
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            if (i == j) continue;
            double d = hypot(cities[i].x - cities[j].x, cities[i].y - cities[j].y);
            if (d + 1e-9 >= 0.25 * (double)R) ODlist.emplace_back(i,j);
        }
    }

    // Precompute s_sq_all using square_flights
    vector<vector<int>> fba_sq = build_flights_by_arrival(square_flights, N);
    vector<vector<vector<int>>> s_sq_all = compute_latest_deps_all(N, square_flights, fba_sq, Tlist);

    // Build initial schedules
    Schedule schedules = build_initial(cities, K);

    // Evaluate initial s_ci and share-rate
    vector<vector<vector<int>>> s_ci_all = compute_s_ci_all(schedules, cities, Tlist);
    long double best_score = compute_share_rate(s_sq_all, s_ci_all, ODlist, Tlist, cities);
    Schedule best_sched = schedules;

    // Random
    mt19937_64 rng((unsigned)chrono::high_resolution_clock::now().time_since_epoch().count());

    // Annealing / local search parameters & time control
    const double TIME_LIMIT = 0.95; // seconds
    const long double T0 = 1.0L; // initial temperature
    const long double Tmin = 1e-6L;

    auto time_start = chrono::high_resolution_clock::now();
    while (true) {
        auto now = chrono::high_resolution_clock::now();
        double elapsed = chrono::duration_cast<chrono::duration<double>>(now - time_start).count();
        if (elapsed > TIME_LIMIT) break;
        long double frac = elapsed / TIME_LIMIT;
        if (frac > 1.0) frac = 1.0;
        long double T = T0 * (1.0L - frac) + Tmin * frac;

        Schedule old_sched = schedules;
        auto res = apply_random_neighbor(schedules, cities, rng);
        if (!res.first) {
            schedules = old_sched;
            continue;
        }

        // compute s_ci_all for new schedules (full recompute)
        vector<vector<vector<int>>> new_s_ci_all = compute_s_ci_all(schedules, cities, Tlist);
        long double new_score = compute_share_rate(s_sq_all, new_s_ci_all, ODlist, Tlist, cities);

        bool accept = false;
        if (new_score > best_score) {
            accept = true;
            best_score = new_score;
            best_sched = schedules;
        } else {
            long double diff = new_score - best_score; // <= 0
            long double prob = expl(diff / max((long double)1e-18, T));
            uniform_real_distribution<long double> ud(0.0L, 1.0L);
            if (ud(rng) < prob) accept = true;
            else accept = false;
        }
        if (!accept) {
            schedules = old_sched; // revert
        }
    }

    // Output best solution in required format
    for (int k = 0; k < K; ++k) {
        if (k < (int)best_sched.size()) {
            const auto &sch = best_sched[k];
            cout << sch.size() << '\n';
            for (const auto &f : sch) {
                cout << (f.a + 1) << " " << fmt_time(f.dep) << " " << (f.b + 1) << " " << fmt_time(f.arr) << '\n';
            }
        } else {
            cout << 0 << '\n';
        }
    }
    return 0;
}
0