Acwing 178 第k短路 (dijkstra+A*)

题面

给定一张N个点(编号1,2…N),M条边的有向图,求从起点S到终点T的第K短路的长度,路径允许重复经过点或边。

注意: 每条最短路中至少要包含一条边。

输入格式
第一行包含两个整数N和M。

接下来M行,每行包含三个整数A,B和L,表示点A与点B之间存在有向边,且边长为L。

最后一行包含三个整数S,T和K,分别表示起点S,终点T和第K短路。

输出格式
输出占一行,包含一个整数,表示第K短路的长度,如果第K短路不存在,则输出“-1”。

数据范围
1≤S,T≤N≤1000,
0≤M≤105,
1≤K≤1000,
1≤L≤100
输入样例:
2 2
1 2 5
2 1 4
1 2 2
输出样例:
14

思路

k短路的板子题,我们先从终点开始跑一边最短路作为我们a里面要用的估价函数。然后去跑A,当我们第k次到达终点,那么这个距离就是我们要求的第k短路。

代码实现

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int maxn=200010;
const int N=1010;
typedef pair<int,int > PII;
typedef pair<int,PII> PIII;

int m,n,s,t,k;
int cnt,tot,head1[maxn],head2[maxn];
int f[N],dis[N],vis[N];
struct edge {
    int w,v,nex;
    edge (int w=0,int v=0,int nex=0) :w(w), v(v), nex(nex) {}
}e1[maxn],e2[maxn];

inline void add1 (int u,int v,int w) {
   e1[++cnt]=edge (w,v,head1[u]);
   head1[u]=cnt;
}

inline void add2 (int u,int v,int w) {
   e2[++tot]=edge (w,v,head2[u]);
   head2[u]=tot;
}


inline void init () {
    memset (vis,0,sizeof (vis));
    memset (dis,0x3f3f3f3f,sizeof (dis));
    memset (head1,-1,sizeof (head1));
    memset (head2,-1,sizeof (head2));
}

inline void dijkstra () {
   priority_queue <PII,vector<PII>,greater <PII> > q;
   dis[t]=0;
   q.push (PII{0,t});

   while (q.size ()) {
       PII u=q.top ();
       q.pop ();

       if (vis[u.second]) continue;
       vis[u.second]=1;
       for (int i=head1[u.second];i!=-1;i=e1[i].nex) {
           int v=e1[i].v;
           if (dis[v]>dis[u.second]+e1[i].w) {
               dis[v]=dis[u.second]+e1[i].w;
               q.push (PII{dis[v],v});
           }
       }
   }
   memcpy (f,dis,sizeof (dis));
}

inline int a_star () {
    priority_queue<PIII,vector<PIII>,greater <PIII> > q;
    
    q.push (PIII{f[s],{0,s}});
    memset (vis,0,sizeof (vis));

    while (q.size ()) {
        PIII u=q.top ();
        q.pop ();

        int ver=u.second.second,distance=u.second.first;
        if (vis[ver]>=k) continue;
        vis[ver]++;
        if (ver==t&&vis[ver]==k) return distance;
        for (int i=head2[ver];i!=-1;i=e2[i].nex) {
            int v=e2[i].v;
            if (vis[v]<k) {
                q.push ({distance+e2[i].w+f[v],{distance+e2[i].w,v}});
            }
        }
    }
    return -1;
}

int main () {
    cin>>n>>m;
    init ();
    for (int i=1;i<=m;i++) {
        int x,y,z;
        cin>>x>>y>>z;
        add2 (x,y,z);
        add1 (y,x,z);
    }   
    cin>>s>>t>>k;
    if (t==s) k++;
    dijkstra ();

    cout<<a_star()<<endl;

    return 0;
}
原文地址:https://www.cnblogs.com/hhlya/p/13361311.html