zoukankan      html  css  js  c++  java
  • 数据结构&图论:K短路-可持久化可并堆

    本来A*就可以搞定的题,为了怕以后卡复杂度,找了个这么个方法

    现阶段水平不够就不补充算法分析部分了

    对于图G,建立一个以终点t为起点的最短路径构成的最短路径树
    (就是反着跑一遍最短路,然后对于一个不为终点的点v,v到终点t的最短路径上(任选一条)v的后继结点为v的父亲,就形成了一棵树)
    然后对于所有点,定义其不在最短路径树上的出边的f值为:f[e] = l[e] + dis[e.tail] - dis[e.head] ,就是走这条边,走到t需要多绕的距离
    那么我们只要找到第k小的这种边的序列就得到解了
    那么我们维护按权值一个从小到大的优先队列,每次从队头取出一个序列q,设q的最后一条边e的head为u,tail为v
    我们可以选择在序列的末尾加上v到t的所有路径上非树边的最小的得到一个新的序列q1
    或者选择u到t的所有路径上所有非树边中e的后继(没用过的边中最小的)替换e得到q2,将q1,q2都塞进优先队列,重复k次,
    可是怎么才能尽快知道一个节点v到t的所有路径上的非树边最小的一个呢?
    打个可持久化的可并堆就没问题了,每个点合并他到根的路径上所有非树出边,然后对于找e的后继替换e的操作,直接找e的两个孩子就行了

    本题难度爆表,低级图论和高级数据结构的大综合

    直接上代码了,以后学的多了再回过头来看方法

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<cstring>
      4 #include<queue>
      5 using namespace std;
      6 const int maxn=8005;  //为啥开这么大??? 
      7 const int maxm=100005;
      8 const int INF=0x7fffffff;
      9 int n,m,cnt,cntf,st,ed,k,tot,tp;
     10 bool vi[maxn];
     11 int g[maxn],gf[maxn],dis[maxn],_next[maxn],root[maxn],sta[maxn];
     12 struct Edge
     13 {
     14     int u,v,w,f,next;
     15     bool vis,flag;
     16 }e[maxm];
     17 struct Edgef
     18 {
     19     int t,w,next;
     20 }ef[maxm];
     21 
     22 void addedge(int x,int y,int z)
     23 {
     24     cnt++;
     25     e[cnt].u=x;e[cnt].v=y;e[cnt].w=z;
     26     e[cnt].next=g[x];g[x]=cnt;
     27     e[cnt].vis=0;
     28 }
     29 void addedgef(int x,int y,int z)
     30 {
     31     cntf++;
     32     ef[cntf].t=y;ef[cntf].w=z;
     33     ef[cntf].next=gf[x];gf[x]=cntf;
     34 }
     35 
     36 struct Node
     37 {
     38     int lc,rc,dis,c,y;
     39 }tr[maxn*100];
     40 int newnode(int c,int y)
     41 {
     42     tot++;
     43     tr[tot].lc=tr[tot].rc=0;
     44     tr[tot].dis=0;
     45     tr[tot].c=c;
     46     tr[tot].y=y;
     47     return tot;
     48 }
     49 int merge(int x,int y)
     50 {
     51     //cout<<x<<" "<<y<<endl;
     52     if(x==0||y==0) return x|y;
     53     if(tr[x].c>tr[y].c) swap(x,y);
     54     int ret=++tot;
     55     tr[ret]=tr[x];
     56     int k=merge(tr[ret].rc,y);
     57     if(tr[tr[ret].lc].dis<=tr[k].dis) swap(tr[ret].lc,k);
     58     tr[ret].rc=k;
     59     tr[ret].dis=tr[tr[ret].lc].dis+1;
     60     return ret;
     61 }
     62 struct HeapNode
     63 {
     64     int x,d;
     65 };
     66 bool operator <(HeapNode x,HeapNode y)
     67 {
     68     return x.d>y.d;
     69 }
     70 priority_queue<HeapNode> q;
     71 
     72 struct Graph
     73 {
     74     int u,x,d;
     75 };
     76 bool operator < (Graph x,Graph y)
     77 {
     78     return x.d>y.d;
     79 };
     80 priority_queue<Graph> Q;
     81 void getdis()
     82 {
     83     dis[ed]=0;
     84     HeapNode temp;
     85     temp.x=ed;temp.d=0;
     86     q.push(temp);
     87     while(!q.empty())
     88     {
     89         HeapNode x=q.top();q.pop();
     90         if(dis[x.x]<x.d) continue;
     91         for(int tmp=gf[x.x];tmp;tmp=ef[tmp].next)
     92         {
     93             int y=ef[tmp].t;vi[y]=1;
     94             if(dis[y]>x.d+ef[tmp].w)
     95             {
     96                 dis[y]=x.d+ef[tmp].w;
     97                 temp.x=y;temp.d=dis[y];
     98                 q.push(temp);
     99             }
    100         }
    101     }
    102 }
    103 void solve(int x)
    104 {
    105     if(x==ed)
    106     {
    107         for(int tmp=g[x];tmp;tmp=e[tmp].next)
    108         {
    109             int y=e[tmp].v;
    110             if(e[tmp].flag==0) continue;
    111             if(e[tmp].vis==0)
    112             {
    113                 root[x]=merge(root[x],newnode(e[tmp].f,e[tmp].v));
    114             }
    115         }
    116         return;
    117     }
    118     for(int tmp=g[x];tmp;tmp=e[tmp].next)
    119     {
    120         int y=e[tmp].v;
    121         if(e[tmp].flag==0) continue;
    122         if(e[tmp].vis==0)
    123             root[x]=merge(root[x],newnode(e[tmp].f,e[tmp].v));
    124         else root[x]=merge(root[x],root[y]);
    125     }
    126 }
    127 int main()
    128 {
    129     int u,v,w;
    130     scanf("%d%d",&n,&m);
    131     for(int i=1;i<=m;i++)
    132     {
    133         scanf("%d%d%d",&u,&v,&w);
    134         addedge(u,v,w);
    135         e[cnt].flag=1;
    136         addedgef(v,u,w);
    137     }
    138     scanf("%d%d%d",&st,&ed,&k);
    139     if(st==ed) k++;
    140     
    141     for(int i=1;i<=n;i++)
    142         dis[i]=INF,vi[i]=0;
    143     getdis();
    144     
    145     if(k==1)
    146     {
    147         if(vi[st]) printf("%d
    ",dis[st]);
    148         else printf("-1
    ");
    149         return 0;
    150     }
    151     for(int i=1;i<=cnt;i++)
    152     {
    153         e[i].f=e[i].w-dis[e[i].u]+dis[e[i].v];
    154         if(dis[e[i].v]==INF) e[i].flag=0;
    155     }
    156     for(int i=1;i<=n;i++)
    157     {
    158         if(i==ed) continue;
    159         for(int tmp=g[i];tmp;tmp=e[tmp].next)
    160         {
    161             v=e[tmp].v;
    162             if(!e[tmp].flag) continue;
    163             if(dis[i]==dis[v]+e[tmp].w)
    164             {
    165                 e[tmp].vis=1;
    166                 _next[i]=v;
    167                 break;
    168             }
    169         }
    170     }
    171     memset(root,0,sizeof(root));
    172     tot=0;
    173     for(int i=1;i<=n;i++)
    174         if(!root[i])
    175         {
    176             if(dis[i]==INF) continue;
    177             sta[tp=1]=i;
    178             while(1)
    179             {
    180                 u=sta[tp];
    181                 if(u==ed) break;
    182                 if(!root[_next[u]]) sta[++tp]=_next[u];
    183                 else break;
    184             }
    185             while(tp)
    186             {
    187                 solve(sta[tp]);
    188                 tp--;
    189             }
    190         }
    191     k-=2;
    192     Graph ss;
    193     ss.u=st;ss.d=tr[root[st]].c;ss.x=root[st];
    194     Q.push(ss);
    195     while(k--)
    196     {
    197         Graph tmp=Q.top();Q.pop();
    198         if(tmp.u==0)
    199         {
    200             printf("-1
    ");
    201             return 0;
    202         }
    203         if(tr[tmp.x].lc)
    204         {
    205             Graph tmp1;
    206             tmp1.u=tmp.u;
    207             tmp1.d=-tr[tmp.x].c;
    208             tmp1.x=merge(tr[tmp.x].lc,tr[tmp.x].rc);
    209             tmp1.d+=tr[tmp1.x].c+tmp.d;
    210             Q.push(tmp1);
    211         }
    212         Graph tmp2;
    213         tmp2.u=tr[tmp.x].y;
    214         tmp2.d=tmp.d+tr[root[tmp2.u]].c;
    215         tmp2.x=root[tmp2.u];
    216         Q.push(tmp2);
    217     }
    218     Graph ans=Q.top();
    219     if(ans.u==0)
    220     {
    221         printf("-1
    ");
    222         return 0;
    223     }
    224     if(vi[st]) printf("%d
    ",dis[st]+ans.d);
    225     else printf("-1
    ");
    226     return 0;
    227 }

    200多行幸亏没出什么调不出来的错误,唉,菜啊

  • 相关阅读:
    +-字符串
    心急的C小加
    明明的随机数
    最大公约数和最小公倍数
    独木舟上的旅行
    背包问题
    喷水装置
    奇数魔方
    栈的应用
    c链表结点的删除和添加
  • 原文地址:https://www.cnblogs.com/aininot260/p/9456891.html
Copyright © 2011-2022 走看看