description
给出一个有n个点的有向图,求从s到t的第k小路径。
Solution
我们可以将便全部反向,跑一下从终点到所有点的最短路。我们设一个点的估价函数g[i]=f[i]+d[i],d[i]表示当前点到终点的距离,f[i]表示当前走到点i的距离。那么我们每次从堆中取出估价函数最小的数,拿他扩展到别的点,并把它加入堆中。假设当前取到的点为终点,那么我们就统计一下答案。
Code
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
const int maxn=200005;
struct code{
int a,b,c;
bool friend operator < (code x,code y){
if (x.a==y.a) return !(x.c<y.c);
return !(x.a<y.a);
}
}g;
priority_queue<code>f;
int first[maxn],last[maxn],next[maxn],d[maxn],value[maxn],v[maxn*10];
int n,m,i,t,j,k,l,x,y,num,s,p,z,q,sum;
int first1[maxn],last1[maxn],next1[maxn],value1[maxn];
bool bz[maxn];
void lian(int x,int y,int z){
last[++num]=y;value[num]=z;next[num]=first[x];first[x]=num;
}
void lian1(int x,int y,int z){
last1[num]=y;value1[num]=z;next1[num]=first1[x];first1[x]=num;
}
void spfa(){
int i=0,j=1,t,k,l,x,y;
memset(d,127,sizeof(d));
v[1]=q;bz[q]=true;d[q]=0;
while (i<j){
x=v[++i];
for (t=first1[x];t;t=next1[t]){
if (d[last1[t]]<=d[x]+value1[t]) continue;
d[last1[t]]=d[x]+value1[t];
if (bz[last1[t]]) continue;
v[++j]=last1[t];bz[last1[t]]=true;
}
bz[x]=false;
}
}
int main(){
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++)
scanf("%d%d%d",&x,&y,&z),lian(x,y,z),lian1(y,x,z);
scanf("%d%d%d",&s,&q,&sum);
spfa();
if (s==q) sum++;
if (d[s]==2139062143){
printf("-1\n");
return 0;
}
g.a=d[s];
g.b=s;
f.push(g);
while (!f.empty()){
g=f.top();
if (g.b==q){
sum--;
if (!sum){
printf("%d\n",g.a);return 0;
}
}
x=g.b;
k=g.a;
l=g.c;
f.pop();
for (t=first[x];t;t=next[t]){
g.a=l+value[t]+d[last[t]];
g.b=last[t];
g.c=l+value[t];
f.push(g);
}
}
printf("-1\n");
}