• 第k短路


    k短路

    1.1 问题引入

    • n个点,m条边的有向图,给出起点s,终点t,求st的第k,短路。

    1.2 问题分析

    • 一条路径可以由两部分组成,第一部分是一个从起点s出发到达任意点x的路径,而第二部分是从x出发,到终点t的最短路径。两部分正好可以组成一条s~t的路径,且每一条路径都可以分解这两部分(允许任意一部分为空)。
    • 因此当我们已知第一部分的路径A时,设第二部分为B,我们可以尝试预估完整的路径A+B的费用(距离)
    • 估价函数为:f(x)=g(x)+h(x)。其中g(x)表示路径s~x的已知长度,而h(x)表示路径x~t的预估最短距离。
    • 求最短路时,我们用的是松弛算法,x到起点s只保留最短的路径,但求第k短路每一条路径都需要保留。

    1.3 算法流程

    1. 对原图建一个反图,求出终点t到任一点的最短距离,相当于求出了任一点到t的最短路,把它当做修正函数h(x)。如果ts的最短路不存在,则无解。
    2. 从起点s开始,扩展其邻接边x,把扩展出来的每一条路径加入到优先队列里,优先队列维护的是对股价函数f(x)=g(x)+h(x)进行排序的小根堆,g(x)表示x到起点s的某一条路径的实际值,h(x)x到终点t的最短距离。
    3. 用数组cnt[x]记录节点x出堆的次数,显然出堆次数表示起点sx目前的路径条数,所以当cnt[u]==k时说明目前已经有k条不同的st的路径。为了保证第k短,每次我们把队首最小的路径出队,并以此点扩展路径,显然先出队的路径比后出队的路径更短。

    1.4 代码实现

    //#include<bits/stdc++.h>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    const int maxn=1000+5,maxm=1e5+5,Inf=0x3f3f3f3f;
    struct Node{
        int pos,hx,gx;
        Node(){};
        Node(int x,int y,int z){pos=x;hx=y;gx=z;}
        bool operator < (const Node &a)const{
            return hx+gx>a.hx+a.gx;
        }
    };
    struct Edge{
        int to,w,next;
    }e[maxm],re[maxm];
    int head[maxn],rhead[maxn],dis[maxn],vis[maxn];
    int n,m,s,t,k;
    void Insert(int u,int v,int w){
        e[++head[0]].to=v;e[head[0]].w=w;e[head[0]].next=head[u];head[u]=head[0];//原图
        re[++rhead[0]].to=u;re[rhead[0]].w=w;re[rhead[0]].next=rhead[v];rhead[v]=rhead[0];//反图
    }
    void spfa(){//对反图跑最短路,求出终点t到任意点的最短路
        queue<int> q;
        memset(dis,0x3f,sizeof(dis));
        dis[t]=0;vis[t]=1;q.push(t);
        while(!q.empty()){
            int u=q.front();q.pop();vis[u]=0;
            for(int i=rhead[u];i;i=re[i].next){
                int v=re[i].to;
                if(dis[v]>dis[u]+re[i].w){
                    dis[v]=dis[u]+re[i].w;
                    if(!vis[v]){
                        q.push(v);vis[v]=1;
                    }
                }
            }
        }
    }
    int astar(){
        if(dis[s]==Inf)return -1;//t到s不可达
        int cnt[maxn]={0};//cnt[i]记录节点i的出队次数
        priority_queue<Node> q;
        q.push(Node(s,0,0));//s:起点,第二为h(s),第三位g(s)
        while(!q.empty()){
            Node temp=q.top();q.pop();
            int u=temp.pos,gx=temp.gx;
            cnt[u]++;//节点u的出队次数
            if(cnt[u]==k && u==t)return gx;
            if(cnt[u]>k)continue;//只需记录起点到u的不超过k条路径,多的路径没意义
            for(int i=head[u];i;i=e[i].next){//从u扩展其他路径
                int v=e[i].to,w=e[i].w;
                q.push(Node(v,dis[v],gx+w));
            }
        }
        return -1;//队列为空u出队次数不到k次,说明不存在第k短路。
    }
    void Solve(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;++i){
            int u,v,w;scanf("%d%d%d",&u,&v,&w);
            Insert(u,v,w);
        }
        scanf("%d%d%d",&s,&t,&k);
        if(s==t)++k;
        spfa();
        printf("%d
    ",astar());
    }
    int main(){
        Solve();
        return 0;
    }
    
    • 此题求得是不严格的第k短路,如果要求严格的最短路改怎么办呢?
  • 相关阅读:
    从IL角度彻底理解回调_委托_指针
    微信个人机器人开发
    个人微信接口开发
    淘客微信接口
    python爬虫添加请求头代码实例
    用 Django 开发一个 Python Web API
    Common encryption methods and implementation in Python Python中常用的加密方法及实现
    python aes加密
    # Python语言程序设计基础
    Python语言程序设计基础——4 程序的控制结构
  • 原文地址:https://www.cnblogs.com/hbhszxyb/p/12978146.html
Copyright © 2020-2023  润新知