我最开始接触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 }