#include #include #include #include #include #include #include #include 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 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& 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 rebuild_schedule_network(int k, int N, const vector& cities) { vector 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 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(now - start_time).count() > 900) break; } int k = rand() % K; vector old_sch = schedules[k]; // 仮に空にして再構築 schedules[k].clear(); update_sci(N, K); vector 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; }