關於 SPFA,
它還苟延殘喘地活著……
題意
一個無向圖,每條邊有兩個權 \(x, y\),求能否透過刪除一些邊使得 \(x\) 的最短路 \(1 \to n\) 不小於 \(T\),輸出刪除的邊的 \(y\) 的最大值的最小值。
題解
觀察到如果我們列舉一個 \(y\) 的最大值 \(k\),我們就可以刪掉所有 \(y \le k\) 的邊(不要錢,不刪白不刪)。
跑 spfa 就行啦。
但是會超時!洗洗睡吧
觀察到題目要求是“最大值最小”,不難想到可以二分 \(k\)。
因為我 \(k\) 增加,對應要刪的邊增加,刪掉的邊越多最短路越大,一定滿足單調性。
不會超時啦!
一個二分的複雜度 \(\log m\),spfa 的抽象時間複雜度 \(mk\)。
\(k\) 是一個由 \(1\) 到 \(n\) 不等的《小》常數(取決於資料強度)。
時間複雜度:\(\mathcal O(mk \log m)\),抽象但是反正能過。
namespace zqh {
const int N = 20005;
int n, m, T;
int dis[N];
bool vis[N];
struct node {
int to;
int tim;
int year;
};
struct edge {
int u, v;
int tim, year;
};
bool operator<(edge x, edge y) {
return x.year < y.year;
}
vector<node> g[N];
vector<edge> e;
void spfa(int s, int jq) {
memset(dis, 0x3f, sizeof(dis));
dis[s] = 0;
queue<int> q;
q.push(s);
vis[s] = true;
while (q.size()) {
int u = q.front();
q.pop();
vis[u] = false;
for (auto [v, t, y] : g[u]) {
if (y <= jq)
continue;
if (dis[v] > dis[u] + t) {
dis[v] = dis[u] + t;
if (!vis[v])
q.push(v), vis[v] = true;
}
}
}
}
void init() {
cin >> n >> m >> T;
for (int i = 1; i <= m; i++) {
int u, v, t, y;
cin >> u >> v >> t >> y;
e.push_back({u, v, t, y});
}
sort(e.begin(), e.end());
for (int i = 0; i < m; i++) {
g[e[i].u].push_back({e[i].v, e[i].tim, e[i].year});
}
}
void solve() {
spfa(1, LLONG_MIN);
if (dis[n] >= T) {
cout << "-1 " << dis[n];
return;
}
int l = 1, r = m, ans = 0;
while (l <= r) {
int mid = (l + r) >> 1;
spfa(1, e[mid - 1].year);
if (dis[n] >= T) {
r = mid - 1;
ans = mid;
} else
l = mid + 1;
}
cout << e[ans - 1].year;
}
void main() {
init();
solve();
}
} // namespace zqh