版权声明:本文为博主原创作品, 转载请注明出处! https://blog.csdn.net/solider98/article/details/84346525
思路分析:
如果直接使用优先队列BFS,将导致的一个直接结果就是内存爆, 考虑采用A*, 使用的估价函数为当前扩展结点x到目标结点T的最短路径, 因此需先预处理所有结点到T的最短路径距离, 这可采用在给定图的转置图上计算结点T到所有结点的最短距离. 可以证明第K次从优先队列中取出点T对应的距离为点S到T的第K短路的长度, 在此基础上给出如下AC代码(注意第38行的if(S == T) ++K; 是必要的, 原因不详):
//POJ2449_Remmarguts' Date
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#include <vector>
#include <functional>
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef pair<int, int> pii; typedef pair<pii, int> piii;
const int MAXN = 1e3 + 5, MAXM = 1e5 + 5, INF = 0x3f3f3f3f;
int N, M, S, T, K; int ver[MAXM << 1], nex[MAXM << 1], we[MAXM << 1], head[MAXN], tot;
int tver[MAXM << 1], tnex[MAXM << 1], twe[MAXM << 1], thead[MAXN], ttot;//转置图信息
int mind[MAXN];
//计算转置图中各顶点到T的最短距离
void calcMind(){
priority_queue<pii, vector<pii>, greater<pii> > pq;
pq.push(mp(0, T)); memset(mind, 0x3f, sizeof(mind));
while(!pq.empty()){
int a = pq.top().fi, b = pq.top().se; pq.pop();
if(mind[b] != INF) continue; mind[b] = a;
for(int i = thead[b], y; i; i = tnex[i])
if(y = tver[i], mind[y] == INF) pq.push(mp(a + twe[i], y));
}
}
int main(){
scanf("%d %d", &N, &M);
for(int i = 1; i <= M; ++i){
int u, v, w; scanf("%d %d %d", &u, &v, &w);
ver[++tot] = v, we[tot] = w;
if(!head[u]) head[u] = tot; else nex[tot] = head[u], head[u] = tot;
tver[++ttot] = u, twe[ttot] = w;
if(!thead[v]) thead[v] = ttot; else tnex[ttot] = thead[v], thead[v] = ttot;
}
scanf("%d %d %d", &S, &T, &K), calcMind(); int cnt = 0, res = INF; if(S == T) ++K;
priority_queue<piii, vector<piii>, greater<piii> > pq; pq.push(mp(mp(mind[S], 0), S));
while(!pq.empty()){
int a = pq.top().fi.se, b = pq.top().se; pq.pop();
if(b == T) ++cnt, res = a; if(cnt == K) break;
for(int i = head[b]; i; i = nex[i]){
int y = ver[i], z = a + we[i]; pq.push(mp(mp(mind[y] + z, z), y));
}
}
if(cnt == K) cout << res << endl; else cout << -1 << endl;
return 0;
}