本题为一道有约束的分层图最短路问题。
跟分层图最短路不一样的是,本题有一个连续 $k$ 短路不需要花费的一个约束条件,那么我们在传递状态的时候只需要特判一下,如果当前的已经使用了免费次数了,那么我们接下来我们松弛的时候就不需要花费。
这里我们使用一个二维数组 $dis_{i,k}$ 表示当前到达第 $i$ 个节点,使用了 $k$ 次免费次数的最短路径,那么我们可以得到状态转移方程:
不需要花费时:$dis_{v,{k-1}} = \min(dis_{v,{k-1}}, dis_{u,k})$。
需要花费时:$dis_{v,k} = \min(dis_{v,k}, dis_{u,k} + w)$。
C++ 代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2000005;
const int inf = 1047483647;
struct node {
int to, next, data;
};
node edge[maxn];
int head[maxn], cnt, k, n, m;
void add_edge(int from, int to, int data) {
edge[++cnt].to = to;
edge[cnt].data = data;
edge[cnt].next = head[from];
head[from] = cnt;
}
int dis[1005][15];
bool vis[1005][15];
struct heap {
int node, data, step;
heap(int n, int d, int s) : node(n), data(d), step(s) {}
bool operator>(const heap& h) const {
return data > h.data;
}
};
void dijkstra() {
memset(vis, 0, sizeof(vis));
memset(dis, 0x3f, sizeof(dis));
dis[0][k] = 0;
priority_queue<heap, vector<heap>, greater<heap>> q;
q.push(heap(0, 0, k));
while (!q.empty()) {
int now = q.top().node;
int step = q.top().step;
q.pop();
if (vis[now][step])
continue;
vis[now][step] = true;
for (int i = head[now]; i != 0; i = edge[i].next) {
int to = edge[i].to, data = edge[i].data;
if (step < k && step > 0 && dis[to][step - 1] > dis[now][step]) {
dis[to][step - 1] = dis[now][step];
q.push(heap(to, dis[to][step - 1], step - 1));
}
else if (step == k || step == 0) {
if (dis[to][step] > dis[now][step] + data) {
dis[to][step] = dis[now][step] + data;
q.push(heap(to, dis[to][step], step));
}
if (step == k && dis[to][step - 1] > dis[now][step]) {
dis[to][step - 1] = dis[now][step];
q.push(heap(to, dis[to][step - 1], step - 1));
}
}
}
}
}
int main() {
cin >> n >> k >> m;
while (m--) {
int x, y, z;
cin >> x >> y >> z;
add_edge(x, y, z);
add_edge(y, x, z);
}
dijkstra();
cout << min(dis[n - 1][k], dis[n - 1][0]) << endl;
return 0;
}