zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    asp.net服务器控件button先执行js再执行后台的方法
    详谈ASP.NET的DataReader对象
    ASP.NET Web API的Controller是如何被创建的?
    富文本编辑器复制粘贴图片上传
    富文本编辑器的使用和图片上传,复制粘贴图片上传
    能够粘贴Word文档公式的编辑器
    可以粘贴Word公式的编辑器
    可以粘贴Word文档公式的编辑器
    可以粘贴Word文档中公式的编辑器
    openstack nova 深入
  • 原文地址:https://www.cnblogs.com/asdfsag/p/12405399.html
Copyright © 2011-2022 走看看