第k短路

4 篇文章 0 订阅
4 篇文章 0 订阅

这可爱的问题,呵呵
启发式搜索的一大旗舰问题
要弄懂它,你先去复习一下可爱的spfa吧…
当然,不怕浪费时间floyd也行
总之能求出单源最短路就行


↓↓复习完的看这里(☄⊙ω⊙)☄↓↓

题目顾名思义,就是求第k短的路径
我们的启发函数该怎么写呢
这是一个不太深奥的问题
f=g+h;
g我们就当作到当前点已经过的路程
h就依然延续以前的想法取当前点到终点的最短距离
那么我们就可以用spfa预处理一个h[i]数组记录终点到第i个点的距离
那么说明一下大概思路
用启发式搜索搜索最短路,但当到达终点时不停止
直到第k次到达终点,就是要求的第k短路
注意: 当起点与终点相同时,由于长度为0没有意义所以第k+1短路为所求


示范:以1节点为起点,n节点为终点(我没判负环φ(゜▽゜*)♪ )

#include <cstdio>
#include <queue>
using namespace std;
typedef long long ll;
const ll inf=1000000000000000000ll;
struct edge1
{
    int to,next;
    ll len;
}da1[100001],da2[100001];
struct edge2
{
    int to;
    ll g,f;
    bool operator <(const edge2 &s)const
    {
        if(f==s.f)
            return g>s.g;
        return f>s.f;
    }
    edge2(){}
};
int head1[10001],head2[10001],cnt[10001];
ll h[10001];
bool v[10001];
int n,r,k,idx,ide;
queue <int> q;
priority_queue <edge2> Q;
void add1(int x,int y,ll z)
{
    da1[++idx].to=y;
    da1[idx].len=z;
    da1[idx].next=head1[x];
    head1[x]=idx;
    return ;
}
void add2(int x,int y,ll z)
{
    da2[++ide].to=y;
    da2[ide].len=z;
    da2[ide].next=head2[x];
    head2[x]=ide;
    return ;
}
void spfa()
{
    for(int i=0;i<n;i++)
        h[i]=inf;
    q.push(n);
    v[n]=true;
    cnt[n]++;
    while(!q.empty())
    {
        int tmp=q.front();
        q.pop();
        v[tmp]=false;
        for(int i=head2[tmp];i;i=da2[i].next)
        {
            int tp=da2[i].to;
            if(h[tp]>h[tmp]+da2[i].len)
            {
                h[tp]=h[tmp]+da2[i].len;
                if(!v[tp])
                {
                    q.push(tp);
                    v[tp]=true;
                }
                if(++cnt[tp]>n) return ;
            }
        }
    }
    return ;
}
ll A_s()
{

    edge2 tmp;
    if(n==1)
        k++;
    int cnt=0,l;
    tmp.to=1;
    tmp.g=0;
    tmp.f=tmp.g+h[tmp.to];
    Q.push(tmp);
    while(!Q.empty())
    {
        tmp=Q.top();
        Q.pop();
        if(tmp.to==n)
        {
            int tp=tmp.g;
            if(tp!=l)
            {
                l=tp;
                cnt++;
            }
        }
        if(cnt==k)
            return tmp.g;
        for(int i=head1[tmp.to];i;i=da1[i].next)
        {
            edge2 tp;
            tp.to=da1[i].to;
            tp.g=tmp.g+da1[i].len;
            tp.f=tp.g+h[tp.to];
            Q.push(tp);
        }
    }
    return -1;
}
int main()
{
    scanf("%d%d%d",&n,&r,&k);
    for(int i=1;i<=r;i++)
    {
        int a,b;
        ll c;
        scanf("%d%d%lld",&a,&b,&c);
        add1(a,b,c);
        add2(b,a,c);
    }
    spfa();
    printf("%lld",A_s());
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值