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

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

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

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

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

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<queue>
  5. using namespace std;
  6. const int maxn=; //为啥开这么大???
  7. const int maxm=;
  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=;
  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*];
  40. int newnode(int c,int y)
  41. {
  42. tot++;
  43. tr[tot].lc=tr[tot].rc=;
  44. tr[tot].dis=;
  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==||y==) 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+;
  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]=;
  84. HeapNode temp;
  85. temp.x=ed;temp.d=;
  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]=;
  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==) continue;
  111. if(e[tmp].vis==)
  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==) continue;
  122. if(e[tmp].vis==)
  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=;i<=m;i++)
  132. {
  133. scanf("%d%d%d",&u,&v,&w);
  134. addedge(u,v,w);
  135. e[cnt].flag=;
  136. addedgef(v,u,w);
  137. }
  138. scanf("%d%d%d",&st,&ed,&k);
  139. if(st==ed) k++;
  140.  
  141. for(int i=;i<=n;i++)
  142. dis[i]=INF,vi[i]=;
  143. getdis();
  144.  
  145. if(k==)
  146. {
  147. if(vi[st]) printf("%d\n",dis[st]);
  148. else printf("-1\n");
  149. return ;
  150. }
  151. for(int i=;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=;
  155. }
  156. for(int i=;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=;
  166. _next[i]=v;
  167. break;
  168. }
  169. }
  170. }
  171. memset(root,,sizeof(root));
  172. tot=;
  173. for(int i=;i<=n;i++)
  174. if(!root[i])
  175. {
  176. if(dis[i]==INF) continue;
  177. sta[tp=]=i;
  178. while()
  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-=;
  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==)
  199. {
  200. printf("-1\n");
  201. return ;
  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==)
  220. {
  221. printf("-1\n");
  222. return ;
  223. }
  224. if(vi[st]) printf("%d\n",dis[st]+ans.d);
  225. else printf("-1\n");
  226. return ;
  227. }

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

数据结构&图论:K短路-可持久化可并堆的更多相关文章

  1. luogu 2483 K短路 (可持久化左偏树)

    题面: 题目大意:给你一张有向图,求1到n的第k短路 $K$短路模板题 假设整个图的边集为$G$ 首先建出以点$n$为根的,沿反向边跑的最短路树,设这些边构成了边集$T$ 那么每个点沿着树边走到点$n ...

  2. 图论(A*算法,K短路) :POJ 2449 Remmarguts' Date

    Remmarguts' Date Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 25216   Accepted: 6882 ...

  3. 图论&搜索:K短路-启发式搜索

    判断第k短路的权值是否小于T 直接把队友的代码拿过来了,一定很经典 #include <iostream> #include <queue> #include <cstr ...

  4. 与图论的邂逅07:K短路

    在做最短路的题时我们不免会碰到许多求次短路的题,然而我们也能很快地想到解决的办法: 用dijkstra跑一遍最短路,当终点第二次被取出时就是次短路了.时间复杂度为O((N+M)logN).实际上前面得 ...

  5. 浅谈k短路算法

    An Old but Classic Problem 给定一个$n$个点,$m$条边的带正权有向图.给定$s$和$t$,询问$s$到$t$的所有权和为正路径中,第$k$短的长度. Notice 定义两 ...

  6. bzoj 1598: [Usaco2008 Mar]牛跑步 [k短路 A*] [学习笔记]

    1598: [Usaco2008 Mar]牛跑步 题意:k短路 ~~貌似A*的题目除了x数码就是k短路~~ \[ f(x) = g(x) + h(x) \] \(g(x)\)为到达当前状态实际代价,\ ...

  7. K短路 (A*算法) [Usaco2008 Mar]牛跑步&[Sdoi2010]魔法猪学院

    A*属于搜索的一种,启发式搜索,即:每次搜索时加一个估价函数 这个算法可以用来解决K短路问题,常用的估价函数是:已经走过的距离+期望上最短的距离 通常和Dijkstra一起解决K短路 BZOJ1598 ...

  8. 算法笔记--次小生成树 && 次短路 && k 短路

    1.次小生成树 非严格次小生成树:边权和小于等于最小生成树的边权和 严格次小生成树:    边权和小于最小生成树的边权和 算法:先建好最小生成树,然后对于每条不在最小生成树上的边(u,v,w)如果我们 ...

  9. P2483 【模板】k短路([SDOI2010]魔法猪学院)

    题目背景 感谢@kczno1 @X_o_r 提供hack数据 题目描述 iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的学习之后,iPig对猪世界 ...

随机推荐

  1. Delphi中Templates代码模板添加注意事项

    今天用Delphi中的代码模板添加一段代码,结果就是有问题,多次测试后,发现是编码需要注意. <?xml version="1.0" encoding="GB231 ...

  2. CSS3实现加载数据动画2

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. Ganglia3.1.7安装与配置(收录)

    一.所需要软件 二.安装过程     1.Ganglia运行平台的安装     2.Ganglia依赖库的安装     3.RRDTool的安装     4.Ganglia的安装 (包括使用yum方式 ...

  4. cmd中可以运行java,但不能运行javac命令

    在cmd中可以运行java,但运行javac命令时提示:'javac' 不是内部或外部命令,也不是可运行的程序或批处理文件. 原因:安装java时把jdk的路径和jre的路径选择成一样,就造成覆盖了. ...

  5. shell -- shift用法

    shift是Unix中非常有用的命令.可以使命令参数左移,从而使脚本程序中命令参数位置不变的情况下依次遍历所有参数.如shift 3表示原来的$4现在变成$1,原来的$5现在变成$2等等,原来的$1. ...

  6. Linux - 信息收集

    1. #!,代表加载器(解释器)的路径,如: #!/bin/bash echo "Hello Boy!" 上面的意思是说,把下面的字符(#!/bin/bash以下的所有字符)统统传 ...

  7. XenServer设置master,摧毁故障主机

    XenServer pool 移除server 设置master 这分为Pool Master是正常还是异常2种情况: 正常情况下可能要对Pool Master做一些停机维护,比如换内存条啥的,此时在 ...

  8. 第十九章 Python os模块,pathlib 判断文件是目录还是文件

    OS模块 os.path.abspath() :返回path规范化的绝对路径 import sys import os BASE_DIR = os.path.dirname(os.path.dirna ...

  9. postgres(pl/pgsql)

    复制后期看 https://www.cnblogs.com/stephen-liu74/archive/2012/06/06/2312759.html https://www.cnblogs.com/ ...

  10. Javascript Array和String的互转换

    Array类可以如下定义: var aValues = new Array(); 如果预先知道数组的长度,可以用参数传递长度 var aValues = new Array(20); -------- ...