原题连接
题意
在m条航线中,可以选择k条路线免费,问从st到ed的最小花费是多少。
观察一下题目数据,n只有2e4而k只有10,因此n*(k+1)个点的时间复杂度也绰绰有余,这时就可以利用分层图的思想来写。
解题思路
将整个图想象成一个三维的立体空间,那么1到n个点排在第一层,n+1到2n的点排在第2层……依次类推,那么我们可以假设层与层之间的联系为免费的路线,每上一层相当于利用一次免费的机会,层之间当然是只上不下,因此如果有k次免费机会,那么就会有k+1层的图,最后答案肯定在每一层的st中找。
#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
const int M = 2000010;
int ne[2 * M], vi[2 * M], e[2 * M], h[N];
int tot, n, m, k, st, ed;
int dis[N], vis[N];
void add(int u, int v, int w) {
e[tot] = v, vi[tot] = w, ne[tot] = h[u], h[u] = tot++;
}
struct node {
int d, now;
bool operator < (const node& x) const {
return d > x.d;
}
};
priority_queue<node> q;
void dijkstra(int s) {
memset(dis, 0x3f, sizeof dis);
dis[s] = 0;
q.push(node{ dis[st], st });
while (q.size()) {
node p = q.top();
q.pop();
int u = p.now;
if (vis[u]) continue;
vis[u] = 1;
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (dis[v] > dis[u] + vi[i]) {
dis[v] = dis[u] + vi[i];
if (!vis[v]) {
q.push(node{ dis[v], v });
}
}
}
}
}
int main() {
cin >> n >> m >> k;
cin >> st >> ed;
st++, ed++;
memset(h, -1, sizeof h);
for (int i = 0; i < m; i++) {
int x, y, z;
cin >> x >> y >> z;
x++, y++;
add(x, y, z), add(y, x, z);
for (int j = 1; j <= k; j++) {
add(x + j * n, y + j * n, z);
add(y + j * n, x + j * n, z);
add(x + (j - 1) * n, y + j * n, 0);
add(y + (j - 1) * n, x + j * n, 0);
}
}
dijkstra(st);
int res = 999999999;
for (int i = ed; i <= (k + 1) * n; i += n) res = min(res, dis[i]);
cout << res << endl;
}