มี n สถานี เชื่อมด้วย m ราง (สองทาง) ต้องเดินทางจาก src ไป dst รางที่ i เชื่อม {station1, station2} จากสถานี j รถไฟออกทุก k_j หน่วยเวลา (คูณของ k_j) และใช้เวลา t_j ถึงสถานีปลายทาง ข้อมูลใน departure = {{t_j, k_j}} สามารถเปลี่ยนรถไฟได้ทันที (เวลาเปลี่ยน = 0) หาเวลาน้อยที่สุดจาก src ถึง dst
ตัวอย่าง: n=4, m=3, src=1, dst=4, roads={{1,2},{2,4},{3,4}}, departure={{2,1},{3,5},{7,6}} ผลลัพธ์: 8 (สถานี 1→2 เวลา 0 ถึงเวลา 2, สถานี 2→4 รอจนเวลา 5 ถึงเวลา 8)
ขั้นตอนการแก้ปัญหา (Dijkstra แบบปรับเปลี่ยน)
- สร้างกราฟ
graphโดยแต่ละขอบเก็บ(ปลายทาง, t, k) - อาร์เรย์
dpเก็บเวลาล่าสุดที่ถึงแต่ละสถานี (เริ่มต้น -9999) - Priority Queue (max-heap โดยเก็บค่าลบ) เริ่มจาก
srcเวลา 0 - ขณะคิวไม่ว่าง:
- ดึง
(w, a)ถ้าa == dstคืน-w - ถ้า
w < dp[a]ข้าม - สำหรับขอบ
(b, t, k)จากaคำนวณweight = (w - k + 1) / k * k - t(เวลาออกเดินทางล่าสุดก่อนถึงa) - ถ้า
weight > dp[b]อัปเดตและ push เข้าคิว
- ดึง
ตัวอย่างโค้ด C++
#include <bits/stdc++.h>
using namespace std;
int solve(int n, int m, int src, int dst,
vector<pair<int, int>> roads,
vector<pair<int, int>> departure) {
src--; dst--;
vector<tuple<int, int, int>> graph[n];
for (int i = 0; i < m; i++) {
int a = roads[i].first - 1;
int b = roads[i].second - 1;
int t = departure[i].first;
int k = departure[i].second;
graph[a].emplace_back(b, t, k);
graph[b].emplace_back(a, t, k);
}
vector<int> dp(n, -9999);
priority_queue<pair<int, int>> priq;
dp[src] = 0;
priq.push({-dp[src], src});
while (!priq.empty()) {
auto [w, a] = priq.top(); priq.pop();
if (a == dst) return -w;
if (w < dp[a]) continue;
for (auto &v : graph[a]) {
int b, t, k;
tie(b, t, k) = v;
int weight = (w - k + 1) / k * k - t;
if (weight > dp[b]) {
dp[b] = weight;
priq.push({weight, b});
}
}
}
return -1;
}
int main() {
int n = 4, m = 3, src = 1, dst = 4;
vector<pair<int, int>> roads = {{1, 2}, {2, 4}, {3, 4}};
vector<pair<int, int>> departure = {{2, 1}, {3, 5}, {7, 6}};
cout << solve(n, m, src, dst, roads, departure);
return 0;
}
อินพุต / เอาต์พุต
Input: 4, 3, 1, 4, {{1, 2}, {2, 4}, {3, 4}}, {{2, 1}, {3, 5}, {7, 6}}
Output: 8