Hướng giải của Sức bền của xe
Nhớ rằng hướng dẫn giải này chỉ nên sử dụng khi bế tắc, và tuyệt đối không nên sao chép mã nguồn kèm theo. Hãy tôn trọng tác giả bài tập và người viết hướng dẫn giải.
Nộp mã nguồn lời giải chính thức trước khi giải bài tập đó có thể khiến bạn bị ban.
Nộp mã nguồn lời giải chính thức trước khi giải bài tập đó có thể khiến bạn bị ban.
Tác giả:
Đây là bài toán tìm đường đi ngắn nhất có điều kiện thay đổi pin liên tục (SPFA đa trạng thái kết hợp reset trạng thái). Ta định nghĩa trạng thái khoảng cách là \(dist[u][p]\): tổng trọng số cạnh nhỏ nhất để đi từ \(S\) đến đỉnh \(u\) với mức pin hiện tại là \(p\) (\(0 \le p \le C\)). Khi xe di chuyển từ \(u\) sang \(v\) qua cạnh có trọng số \(w\):
- Mức pin mới dự kiến là \(next\_p = p - w\).
- Nếu \(next\_p > C\), ta thu hẹp lại \(next\_p = C\).
- Xe chỉ đi qua được nếu \(next\_p \ge 0\).
- Nếu đỉnh \(v\) là một trạm sạc đặc biệt, mức pin sẽ tự động cập nhật lên \(next\_p = C\).
- Trạng thái mới thu được là \(dist[v][next\_p] = dist[u][p] + w\). Chúng ta chạy SPFA trên không gian \(N imes (C+1)\) trạng thái để tìm kết quả tối ưu.
Mã nguồn C++ mẫu
#include <bits/stdc++.h>
using namespace std;
const long long INF = 1e18;
struct State {
int u, p;
};
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n, m, max_p, s, t, num_stations;
if (!(cin >> n >> m >> max_p >> s >> t >> num_stations)) return 0;
vector<bool> is_station(n + 1, false);
for (int i = 0; i < num_stations; i++) {
int x;
if (cin >> x) is_station[x] = true;
}
vector<vector<pair<int, int>>> adj(n + 1);
for (int i = 0; i < m; i++) {
int u, v, w;
if (cin >> u >> v >> w) {
adj[u].push_back({v, w});
}
}
vector<vector<long long>> dist(n + 1, vector<long long>(max_p + 1, INF));
vector<vector<bool>> in_queue(n + 1, vector<bool>(max_p + 1, false));
dist[s][max_p] = 0;
queue<State> q;
q.push({s, max_p});
in_queue[s][max_p] = true;
while (!q.empty()) {
auto [u, p] = q.front();
q.pop();
in_queue[u][p] = false;
for (auto& edge : adj[u]) {
int v = edge.first;
int w = edge.second;
int next_p = p - w;
if (next_p > max_p) next_p = max_p;
if (next_p >= 0) {
if (is_station[v]) next_p = max_p;
long long next_cost = dist[u][p] + w;
if (next_cost < dist[v][next_p]) {
dist[v][next_p] = next_cost;
if (!in_queue[v][next_p]) {
q.push({v, next_p});
in_queue[v][next_p] = true;
}
}
}
}
}
long long ans = INF;
for (int p = 0; p <= max_p; p++) {
ans = min(ans, dist[t][p]);
}
if (ans == INF) cout << -1 << "\n";
else cout << ans << "\n";
return 0;
}
Nhận xét