原题地址:http://poj.org/problem?id=2449
#include <cmath>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <cctype>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define MOD 1e9+7
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define CLR(x,y) memset((x),y,sizeof(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e5 + 5;
int u[maxn], v[maxn], w[maxn];
struct node {
int v, w, nxt;
bool operator <(const node &a)const {
return w > a.w;
}
node() {}
node(int a, int b): v(a), w(b) {}
} e[maxn];
int n, m, cnt, start, last, k;
int head[maxn];
void init_head() {
cnt = 0;
memset(head, -1, sizeof(head));
}
void add_edge(int u, int v, int w) {
e[++cnt].v = v;
e[cnt].w = w;
e[cnt].nxt = head[u];
head[u] = cnt;
}
int vis[maxn], dis[maxn];
void dij(int num) {
memset(dis, 0x3f, sizeof(dis));
memset(vis, 0, sizeof(vis));
priority_queue<node>q;
q.push(node(num, 0));
dis[num] = 0;
while(!q.empty()) {
int u = q.top().v;
q.pop();
if(vis[u]) continue;
vis[u] = 1;
for(int i = head[u]; ~i; i = e[i].nxt) {
int v = e[i].v;
if(dis[v] > dis[u] + e[i].w) {
dis[v] = dis[u] + e[i].w;
q.push(node(v, dis[v]));
}
}
}
}
struct AS {
int u, g, h; //分别表示顶点,g是当前的精确值,h是估计值
bool operator < (const AS & a)const {
return g + h > a.g + a.h;
}
AS() {}
AS(int u, int g, int h): u(u), g(g), h(h) {}
};
int ans;
void A_star() {
int num = 0;
ans = 0;
if(start == last) k++; //如果起点和终点是同一个点,那么说明最短的就是0,所以可以加1了
if(dis[start] == INF) {
ans = -1;
return;
}
priority_queue<AS>q;
q.push(AS(start, 0, dis[start]));
while(!q.empty()) {
AS tmp = q.top();
q.pop();
if(tmp.u == last) num++;//如果到达说明离第k大距离又近了一步
if(k == num) {//如果已经是最第k大最退出
ans = tmp.g;
return;
}
for(int i = head[tmp.u]; ~i; i = e[i].nxt) {
int v = e[i].v;
q.push(AS(v, tmp.g + e[i].w, dis[v]));
}
}
ans = -1;//如果不存在第k大,就标记并退出
return;
}
int main() {
init_head();
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i++) {
scanf("%d%d%d", &u[i], &v[i], &w[i]);
add_edge(v[i], u[i], w[i]);//反向建边求估计值
}
scanf("%d%d%d", &start, &last, &k);
dij(last);
init_head();//再次初始化建正向边
for(int i = 1; i <= m; i++) {
add_edge(u[i], v[i], w[i]);
}
A_star();
printf("%d\n", ans);
return 0;
}