题意:
给定一个有向图,求第k短路。
思路:
由于要求第k短路,所以只要保证spfa在每次扩展节点时都是当前的最短路,那么当第k次扩展到t的时候就是第k短路。
那么如何求当前的最短路呢?
假设有两个节点i,j,当前的距离分别为i.dist和j.dist,从i,j到终点t的最短路分别为d[i],d[j].
那么,从i到终点最少需要i.dist + d[i]的路程,从j到终点最少需要j.dist + d[j]的路程。
若i.dist + d[i] < j.dist + d[j],那么从j走绝对不可能是当前的最短路。
所以每次扩展v.dist + d[v]最小的节点,扩展到t的时候一定是当前的最短路。
至于d数组可以先对反向图以t为源点做一次spfa求出。
还要注意当s==t时k要加1,因为站着不动不算一条路。
完整代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#define INF 0x3f
using namespace std;
struct Node{
int v, dist, tot;
Node() {}
Node(int a, int b, int c) : v(a), dist(b), tot(c) {}
bool operator < (const Node &n) const {
if (tot != n.tot)
return tot > n.tot;
return dist < n.dist;
}
};
struct Edge{
int to, value;
Edge(int a, int b) : to(a), value(b) {}
};
int V, E;
int s, t, k;
Node start;
vector<Edge> edges[1005], redges[1005];
void addEdge(int from, int to, int value) {
edges[from].push_back(Edge(to, value));
redges[to].push_back(Edge(from, value));
}
int dist[1005];
void spfa() {
bool vis[1005];
memset(vis, 0, sizeof(vis));
memset(dist, 0x3f, sizeof(dist));
queue<int> q;
dist[t] = 0;
vis[t] = 1;
q.push(t);
while (!q.empty()) {
int cur = q.front();
q.pop();
for (int i = 0; i < redges[cur].size(); i++) {
Edge e = redges[cur][i];
if (dist[cur] + e.value < dist[e.to]) {
dist[e.to] = dist[cur] + e.value;
if (!vis[e.to]) {
vis[e.to] = 1;
q.push(e.to);
}
}
}
vis[cur] = 0;
}
}
priority_queue<Node> q;
int spfaAstar() {
if (dist[s] == INF) return -1;
q.push(start);
if (s == t) k++;
int cnt = 0;
while (!q.empty()) {
Node cur = q.top();
q.pop();
if (cur.v == t) {
cnt++;
if (cnt == k) return cur.dist;
}
for (int i = 0; i < edges[cur.v].size(); i++) {
Edge e = edges[cur.v][i];
q.push(Node(e.to, cur.dist + e.value, cur.dist + e.value + dist[e.to]));
}
}
return -1;
}
int main() {
scanf("%d %d", &V, &E);
int a, b, c;
for (int i = 0; i < E; i++) {
scanf("%d %d %d", &a, &b, &c);
addEdge(a, b, c);
}
scanf("%d %d %d", &s, &t, &k);
spfa();
start = Node(s, 0, dist[s]);
int ans = spfaAstar();
cout << ans << endl;
return 0;
}