• K短路问题模板(spfa+A*)


    k短路问题

    给一个图,起点s、终点t、k,求起点到终点的第k短路。
    基本思路:
    首先spfa求出反向图中求出终点t到其他所有点的距离(预处理)
    再从起点开始使用优先队列进行宽搜,用cnt记录到达终点的次数,当cnt==k时的路径长度即为所得。
    搜索的方向用一个估价函数f=g+dis来确定,其中g表示起点到当前点的路径长度,dis表示当前点到终点的最短路径(即之前的预处理),每次扩展估价函数值最小的一个。

    #include<iostream>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int maxn=100010;
    int n,m,dis[maxn];
    int tot,head1[maxn],head2[maxn];
    bool flag[maxn];
    struct edge
    {
        int to;
        int w;
        int next;
    }e[maxn*2],e2[maxn*2];
    struct node
    {
        int f;//f=g+dis dis表示当前点到终点的最短路径,即之前的预处理
        int g;//g表示到当前点的路径长度
        int from;
        bool operator < (node a)const
        {
            if(a.f==f)
            return g>a.g;//重载 小的在前面 
            return f>a.f;
        }
    };
    void add_edge(int u,int v,int w)
    {
        tot++;
        e[tot].to=v;
        e[tot].w=w;
        e[tot].next=head1[u];
        head1[u]=tot;
        e2[tot].to=u;//建反图
        e2[tot].w=w;
        e2[tot].next=head2[v];
        head2[v]=tot;
    }
    void spfa(int t)//反图预处理dis
    {
        for(int i=1;i<=n;i++)
        dis[i]=maxn;
        dis[t]=0;
        queue<int> q;
        q.push(t);
        flag[t]=1;
        while(!q.empty())
        {
            int v=q.front();
            q.pop();flag[v]=0;
            for(int i=head2[v];i;i=e2[i].next)
            if(dis[e2[i].to]>dis[v]+e2[i].w)
            {
                dis[e2[i].to]=dis[v]+e2[i].w;
                if(!flag[e2[i].to])
                {
                    q.push(e2[i].to);
                    flag[e2[i].to]=1;
                }
            }
        }
    }
    int a_star(int s,int t,int k)
    {
        if(s==t) return 0;
        if(dis[s]==maxn) return -1;
        priority_queue<node> q;
        int cnt=0;
        node tmp,to;
        tmp.from=s;
        tmp.g=0;
        tmp.f=tmp.g+dis[tmp.from];
        q.push(tmp);
        while(!q.empty())
        {
            tmp=q.top();
            q.pop();
            if(tmp.from==t) cnt++;
            if(cnt==k) return tmp.g;
            for(int i=head1[tmp.from];i;i=e[i].next)
            {
                to.from=e[i].to;
                to.g=tmp.g+e[i].w;
                to.f=to.g+dis[to.from];
                q.push(to);
            }
        }
        return -1;
    }
    int main()
    {
        int x,y,z,s,t,k;
        cin>>n>>m;
        for(int i=1;i<=m;i++)
        {
            cin>>x>>y>>z;
            add_edge(x,y,z);
        }
        cin>>s>>t>>k;//输入起点,终点,k短路
        spfa(t);
        int ans=a_star(s,t,k);
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    牛影传说【线段树+BFS序运用】
    动态规划 :传纸条
    CQYZ-OJ P1377 危险的组合
    使用 git 管理你的配置文件
    Exponential Distribution
    初尝 C++ 类设计
    Android刷机的一般步骤
    重装 Linux 记录
    Linux 折腾记录 (非正式)
    最大熵对应的概率分布
  • 原文地址:https://www.cnblogs.com/cax1165/p/6070963.html
Copyright © 2020-2023  润新知