k短路问题 (优先队列+可持久化左偏树)

我最开始接触k短路时用的是A*算法,后来我从某位大佬那里得知A*算法的复杂度不稳定,可能会退化成平方级别的(比如,所有结点首尾相连成环)

(注:A*算法不会降低时间复杂度!不用A*算法,用一个普通的优先队列照样可以做,复杂度是一样的,就是A*在一般情况下更快而已)

于是学了下用可持久化可并堆维护数据结构的做法,在此mark一下。

原理比较复杂(但实际上理解了之后很简单),详见余鼎力大牛的课件,大概是利用最短路径树的原理,每次只需把一条树边改成另一条非树边即可得到一条更长的路径,避免了大量无用结点的产生,复杂度$O(nlogn+mlogm+k logk)$(也有把mlogm换成m的做法,但过于复杂就没有写(话说我咋感觉那种做法还是mlogm的呢?存疑ing...))

可并堆有多种实现方式,这里用了左偏树(因为复杂度是单次操作严格的(可持久化),而且代码比较好写)

例题

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 const int N=1e4+10,mod=1e9+7,inf=0x3f3f3f3f;
  5 int n,m,S,T,k,d[N];
  6 ll ans[N];
  7 struct E {
  8     int v,c;
  9     bool operator<(const E& b)const {return c<b.c;}
 10 };
 11 vector<E> g1[N],g2[N];
 12 void link(int u,int v,int c) {
 13     g1[u].push_back({v,c});
 14     g2[v].push_back({u,c});
 15 }
 16 struct Dij {
 17     struct D {
 18         int u,g;
 19         bool operator<(const D& b)const {return g>b.g;}
 20     };
 21     priority_queue<D> q;
 22     void upd(int u,int ad) {if(d[u]>ad)d[u]=ad,q.push({u,ad});}
 23     void solve(int S,int T) {
 24         while(q.size())q.pop();
 25         for(int i=1; i<=n; ++i)d[i]=inf;
 26         upd(S,0);
 27         while(q.size()) {
 28             int u=q.top().u,g=q.top().g;
 29             q.pop();
 30             if(g!=d[u])continue;
 31             for(int i=0; i<g2[u].size(); ++i) {
 32                 int v=g2[u][i].v,c=g2[u][i].c;
 33                 upd(v,g+c);
 34             }
 35         }
 36     }
 37 } dij;
 38 #define l(u) ch[u][0]
 39 #define r(u) ch[u][1]
 40 struct Kth {
 41     static const int M=1e6+10;
 42     int ds[M],ch[M][2],rt[N],tot;
 43     E val[M];
 44     int newnode(E x) {int u=++tot; ds[u]=l(u)=r(u)=0,val[u]=x; return u;}
 45     int cpy(int u) {int w=++tot; ds[w]=ds[u],l(w)=l(u),r(w)=r(u),val[w]=val[u]; return w;}
 46     struct D {
 47         int u;
 48         ll g;
 49         bool operator<(const D& b)const {return g>b.g;}
 50     };
 51     void mg(int& w,int u,int v) {
 52         if(!u||!v) {w=u|v; return;}
 53         if(val[v]<val[u])swap(u,v);
 54         w=cpy(u);
 55         mg(r(w),r(u),v);
 56         if(ds[r(w)]>ds[l(w)])swap(l(w),r(w));
 57         ds[w]=ds[r(w)]+1;
 58     }
 59     int nxt[N],vis[N];
 60     priority_queue<D> q;
 61     void dfs(int u) {
 62         if(vis[u])return;
 63         vis[u]=1;
 64         if(~nxt[u]) {
 65             dfs(g1[u][nxt[u]].v);
 66             rt[u]=rt[g1[u][nxt[u]].v];
 67         }
 68         for(int i=0; i<g1[u].size(); ++i)
 69             if(i!=nxt[u]&&g1[u][i].c!=inf)
 70                 mg(rt[u],rt[u],newnode(g1[u][i]));
 71     }
 72     void solve(int S,int T) {
 73         if(d[S]==inf)return;
 74         for(int u=1; u<=n; ++u)nxt[u]=-1;
 75         for(int u=1; u<=n; ++u)
 76             for(int i=0; i<g1[u].size(); ++i) {
 77                 if(d[g1[u][i].v]==inf)g1[u][i].c=inf;
 78                 else {
 79                     g1[u][i].c-=d[u]-d[g1[u][i].v];
 80                     if(!g1[u][i].c)nxt[u]=i;
 81                 }
 82             }
 83         ds[0]=-1;
 84         tot=0;
 85         for(int u=1; u<=n; ++u)vis[u]=0;
 86         for(int u=1; u<=n; ++u)dfs(u);
 87         while(q.size())q.pop();
 88         q.push({newnode({S,0}),d[S]});
 89         int K=0;
 90         while(q.size()) {
 91             int u=q.top().u;
 92             ll g=q.top().g;
 93             q.pop();
 94             ans[++K]=g;
 95             if(K==k)return;
 96             if(l(u))q.push({l(u),g-val[u].c+val[l(u)].c});
 97             if(r(u))q.push({r(u),g-val[u].c+val[r(u)].c});
 98             if(rt[val[u].v])q.push({rt[val[u].v],g+val[rt[val[u].v]].c});
 99         }
100     }
101 } kth;
102 int main() {
103     scanf("%d%d%d",&n,&m,&k);
104     scanf("%d%d",&S,&T);
105     while(m--) {
106         int u,v,c;
107         scanf("%d%d%d",&u,&v,&c);
108         link(u,v,c);
109     }
110     for(int i=1; i<=k; ++i)ans[i]=-1;
111     dij.solve(T,S);
112     kth.solve(S,T);
113     for(int i=1; i<=k; ++i) {
114         if(~ans[i])printf("%lld
",ans[i]);
115         else puts("NO");
116     }
117     return 0;
118 }
原文地址:https://www.cnblogs.com/asdfsag/p/12405399.html