P4568 [JLOI2011] 飞行路线
解析
对比最基础的最短路,这个加上了可以在有限次数内乘坐任意航班免费的条件
贪心为什么是错的?
你用样例跑一遍基础dij会发现,选了都是5的那条路,但是你肯定发现走带100的那条路更好,100可以免掉
分层图

引用自洛谷用户:SuperJvRuo
仔细发现,上面的克隆了一份到下面,而那些边权为0的边(他没标),就是免费的航班,好理解的,当你用了0次免费机会你就还在上面(1 ~ 4),用了1次免费机会你会在下面(5 ~ 9),于是有几个k你就克隆几份在下面,然后连上就可以,你就向下的连边是单向的,不用担心走回来,用dij跑这个大图就可以了
注意,不要想当然的最下面那个部分的中点,存在前面直接全免的情况
代码
#include <bits/stdc++.h>
using namespace std;
constexpr int N = 1e6 + 2;
int n, m, k, s, t, f[N], d[N];
vector<pair<int, int>> a[N];
inline void dij(int s) {
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
memset(d, 127, sizeof d);
d[s] = 0;
q.push({0, s});
while (!q.empty()) {
auto p = q.top();
q.pop();
int now = p.second;
if (p.first > d[now]) continue;
if (f[now]) continue;
f[now] = true;
for (auto i : a[now]) {
int x = i.first, y = i.second;
if (d[x] > d[now] + y) {
d[x] = d[now] + y;
q.push({d[x], x});
}
}
}
}
inline void read() {
cin >> n >> m >> k;
cin >> s >> t;
for (int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
a[u].push_back({v, w});
a[v].push_back({u, w});
for (int j = 1; j <= k; j++) {
a[u + (j - 1) * n].push_back({v + j * n, 0});
a[v + (j - 1) * n].push_back({u + j * n, 0}); // 别忘了克隆也要连边哦
a[u + j * n].push_back({v + j * n, w});
a[v + j * n].push_back({u + j * n, w});
}
}
}
signed main() {
read();
dij(s);
int ans = 1e9;
for (int i = 0; i <= k; i++) {
ans = min(ans, d[t + i * n]);
}
cout << ans << endl;
return 0;
}
看懂?点赞?

浙公网安备 33010602011771号