第k小路径

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(){
    //freopen("data.in","r",stdin);
    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");
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值