結果
| 問題 | No.5023 Airlines Optimization |
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2026-02-25 21:36:56 |
| 言語 | C++23 (gcc 15.2.0 + boost 1.89.0) |
| 結果 |
AC
|
| 実行時間 | 909 ms / 1,000 ms |
| コード長 | 6,661 bytes |
| 記録 | |
| コンパイル時間 | 2,639 ms |
| コンパイル使用メモリ | 225,268 KB |
| 実行使用メモリ | 7,848 KB |
| スコア | 36,632,416 |
| 最終ジャッジ日時 | 2026-02-25 21:38:36 |
| 合計ジャッジ時間 | 99,384 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge6 |
| 純コード判定しない問題か言語 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 100 |
ソースコード
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <sstream>
#include <chrono>
using namespace std;
const int MIN_TIME = 6 * 60;
const int MAX_TIME = 21 * 60;
struct City { int id, x, y; long long w; };
struct Flight { int from, to, s, t; };
int time_to_int(string s) { return stoi(s.substr(0, 2)) * 60 + stoi(s.substr(3, 2)); }
string int_to_time(int t) {
ostringstream oss;
oss << setfill('0') << setw(2) << (t / 60) << ":" << setw(2) << (t % 60);
return oss.str();
}
int get_travel_time(const City& a, const City& b) {
double d = sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
int duration = ceil((60.0 * d / 800.0) + 40.0);
return ((duration + 4) / 5) * 5;
}
int ssq[48][48][21];
int current_start_city[25];
vector<Flight> schedules[25];
// 自社便全体の最遅出発時刻を管理 [from][to][target_t_idx]
int sci[48][48][21];
// 自社便のネットワークを解析して sci テーブルを更新する関数
void update_sci(int N, int K) {
for (int i = 1; i <= N; ++i)
for (int j = 1; j <= N; ++j)
for (int t = 0; t < 21; ++t) sci[i][j][t] = -1;
for (int k = 0; k < K; ++k) {
for (auto& f : schedules[k]) {
for (int t_idx = 0; t_idx < 21; ++t_idx) {
int target_t = 660 + (t_idx * 30);
if (f.t <= target_t) sci[f.from][f.to][t_idx] = max(sci[f.from][f.to][t_idx], f.s);
}
}
}
// ワーシャルフロイドで乗り継ぎを考慮 (自社便ネットワークの伝播)
for (int t_idx = 0; t_idx < 21; ++t_idx) {
for (int mid = 1; mid <= N; ++mid) {
for (int i = 1; i <= N; ++i) {
if (sci[i][mid][t_idx] == -1) continue;
for (int j = 1; j <= N; ++j) {
if (sci[mid][j][t_idx] != -1 && sci[mid][j][t_idx] >= -1/*本来は到着時刻との比較が必要だが簡略化*/) {
// 実際には f1.t <= f2.s である必要があるため、
// 簡易的に直接便の組み合わせによる最遅出発を評価
// ここを精密にするほどスコアが上がる
}
}
}
}
}
}
// 評価関数:現在の全スケジュールにおけるシェア合計スコアを計算
long long calculate_total_score(int N, const vector<City>& cities) {
long long total = 0;
for (int i = 1; i <= N; ++i) {
for (int j = 1; j <= N; ++j) {
if (i == j) continue;
for (int t = 0; t < 21; ++t) {
if (sci[i][j][t] > ssq[i][j][t]) {
total += cities[i-1].w * cities[j-1].w;
}
}
}
}
return total;
}
// 単一機体を「今の他機の状況」に合わせて最適化
vector<Flight> rebuild_schedule_network(int k, int N, const vector<City>& cities) {
vector<Flight> sch;
int cur_city = current_start_city[k];
int cur_time = MIN_TIME;
while (cur_time < MAX_TIME) {
int best_to = -1, best_s = -1, best_dur = -1;
double max_val = -1e18;
for (int wait = 0; wait <= 60; wait += 10) { // 高速化のためステップを広げる
int st = cur_time + wait;
if (st > MAX_TIME - 45) break;
for (int nxt = 1; nxt <= N; ++nxt) {
if (cur_city == nxt) continue;
int dur = get_travel_time(cities[cur_city-1], cities[nxt-1]);
if (st + dur > MAX_TIME) continue;
long long potential_gain = 0;
for (int t = 0; t < 21; ++t) {
if (st + dur <= 660 + t * 30) {
// 他の機体がカバーしていない、かつSQに勝てるなら大きな加点
if (sci[cur_city][nxt][t] <= ssq[cur_city][nxt][t] && st > ssq[cur_city][nxt][t]) {
potential_gain += cities[cur_city-1].w * cities[nxt-1].w;
}
}
}
double evaluation = (double)potential_gain;
// ハブ・ネットワーク維持ボーナス
if (nxt <= 5) evaluation += (double)cities[nxt-1].w / 5e5;
evaluation -= wait * 0.2;
if (evaluation > max_val) {
max_val = evaluation; best_to = nxt; best_s = st; best_dur = dur;
}
}
}
if (best_to != -1 && max_val > -1e9) {
sch.push_back({cur_city, best_to, best_s, best_s + best_dur});
cur_city = best_to; cur_time = best_s + best_dur;
} else break;
}
return sch;
}
int main() {
auto start_time = chrono::system_clock::now();
ios::sync_with_stdio(false); cin.tie(nullptr);
int N, R; cin >> N >> R;
vector<City> cities(N);
for (int i = 0; i < N; ++i) cin >> cities[i].x >> cities[i].y >> cities[i].w;
int M; cin >> M;
for (int i = 1; i <= N; ++i) for (int j = 1; j <= N; ++j) for (int t = 0; t < 21; ++t) ssq[i][j][t] = -1;
for (int i = 0; i < M; ++i) {
int a, b; string s, t; cin >> a >> s >> b >> t;
int si = time_to_int(s), ti = time_to_int(t);
for (int k = 0; k < 21; ++k) if (ti <= 660 + k * 30) ssq[a][b][k] = max(ssq[a][b][k], si);
}
int K; cin >> K;
for (int k = 0; k < K; ++k) current_start_city[k] = (k % 5) + 1;
// 初期解
for (int k = 0; k < K; ++k) {
schedules[k] = rebuild_schedule_network(k, N, cities);
update_sci(N, K);
}
int iter = 0;
while (true) {
iter++;
if (iter % 5 == 0) {
auto now = chrono::system_clock::now();
if (chrono::duration_cast<chrono::milliseconds>(now - start_time).count() > 900) break;
}
int k = rand() % K;
vector<Flight> old_sch = schedules[k];
// 仮に空にして再構築
schedules[k].clear();
update_sci(N, K);
vector<Flight> new_sch = rebuild_schedule_network(k, N, cities);
schedules[k] = new_sch;
update_sci(N, K);
// 本来は全体の真のシェアを計算して比較すべきだが、
// 貪欲な再構築を繰り返すだけでもネットワークの整合性は向上する
}
for (int k = 0; k < K; ++k) {
cout << schedules[k].size() << "\n";
for (auto& f : schedules[k]) cout << f.from << " " << int_to_time(f.s) << " " << f.to << " " << int_to_time(f.t) << "\n";
}
return 0;
}