疫情延迟 题解
关于 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
但在我的心中,它已经死了……

浙公网安备 33010602011771号