第k短路的求法

25 篇文章 8 订阅
18 篇文章 0 订阅

Description

从一个点s到t的第k短的路径。

Solution

我以前只会打从一个点到另一个点的最短路径。
后来去看了看k短路径的求法。

A_Star算法

设估价函数 g[i]=f[i]+p[i] f[i] 表示i到t的最短路径的长度, p[i] 表示s到i目前走得距离。
首先,我们把原图的边全部反向连边。然后求出所有的点到t的最短路径。
然后,我们把s丢进堆里面,堆的判断大小条件以g为第一关键字,f为第二关键字。
每次取出堆顶a,把它弹出去,如果弹出去的是t,那么cnt++(表示找到了第cnt短路),如果cnt=k,那么就退出 。
把与a向连的点,计入f和g,丢进堆里面。
这样就可以了。

例题

POJ2249

Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define rep(i,a) for(i=first[a];i;i=next[i])
#define rep1(i,a) for(i=first1[a];i;i=next1[i])
using namespace std;
const int maxn=200007;
int i,j,k,l,n,m,ans,x,y,z,ss,tt;
int first[maxn],last[maxn],next[maxn],chang[maxn],num;
int first1[maxn],last1[maxn],next1[maxn],chang1[maxn],num1;
int d[maxn],data[maxn*10];
bool bz[maxn];
struct node{
    int a,g,f;
    bool friend operator <(node x,node y){
        if(x.g==y.g)return !(x.f<y.f);
        return !(x.g<y.g);
    }
}o,p;
priority_queue<node> t;
void add(int x,int y,int z){
    last[++num]=y,next[num]=first[x],first[x]=num,chang[num]=z;
}
void add1(int x,int y,int z){
    last1[++num1]=y,next1[num1]=first1[x],first1[x]=num1,chang1[num1]=z;
}
void spfa(int x){
    int head=0,tail=1,i,now;
    memset(d,127,sizeof(d));
    data[1]=x,d[x]=0,bz[x]=1;
    while(head<tail){
        now=data[++head];
        rep1(i,now){
            if(d[now]+chang1[i]<d[last1[i]]){
                d[last1[i]]=d[now]+chang1[i];
                if(!bz[last1[i]]){
                    bz[last1[i]]=1;
                    data[++tail]=last1[i];
                }
            }
        }
        bz[now]=0;
    }
}
void a_star(){
    int i;
    if(ss==tt)k++;
    if(d[ss]==2139062143)return;
    o.a=ss,o.f=0,o.g=d[ss];t.push(o);
    while(!t.empty()){
        p=t.top();
        t.pop();
        if(p.a==tt)k--;
        if(!k){
            ans=p.f;
            return;
        }
        rep(i,p.a){
            o.a=last[i];
            o.f=p.f+chang[i];
            o.g=o.f+d[last[i]];
            t.push(o);
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    fo(i,1,m){
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
        add1(y,x,z);
    }
    scanf("%d%d%d",&ss,&tt,&k);
    ans=-1;
    spfa(tt);
    a_star();
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值