在做最短路的题时我们不免会碰到许多求次短路的题,然而我们也能很快地想到解决的办法:

用dijkstra跑一遍最短路,当终点第二次被取出时就是次短路了。时间复杂度为O((N+M)logN)。实际上前面得乘个2.

那么根据OI的尿性,有了最优解问题,又有了次优解问题,接下来是什么?K优解!那么K短路怎么做?

仍然可以用上面的方法,用dijkstra不停地跑,直到终点被第k次取出时就是K短路。时间复杂度就是:O(K*(N+M)logN)。然而这种复杂度随便上网搜一道模板题都跑不过。

其实dijkstra可以看成加了优先队列的广度优先搜索。为了优化这种搜索,我们唯独可以在它的堆里面动点手脚。这时就要用到神奇的A*算法了。

根据设计估价函数的原则,其估计值f[x]不能大于其实际值,即无论K为多少时,f[x]都要小于等于x到终点的第K短路。通俗一点,设x到终点的所有path共同构成一个集合S:

\[{\forall}path{\in}S,f[x]{\leq}lenth[path]
\]

设x到终点的最短路为ShortestPath,上面的式子可以简化为:

\[f[x]{\leq}ShortestPath
\]

而这意味着我们直接令f[x]=ShortestPath就可以了!

所以我们首先预处理出所有点的预估值。具体操作是:建立反图,从终点开始跑出每个点的最短路的长度作为预估值。

然后我们每次只需要从堆里面取出dis[x]+f[x]最小的那个即可。当终点被第K次取出时就是K短路。

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<queue>
  5. #define maxn 1001
  6. #define maxm 100001
  7. using namespace std;
  8. struct graph{
  9. struct edge{
  10. int to,dis,next;
  11. edge(){}
  12. edge(const int &_to,const int &_dis,const int &_next){ to=_to,dis=_dis,next=_next; }
  13. }e[maxm];
  14. int head[maxn],k;
  15. inline void init(){ memset(head,-1,sizeof head); }
  16. inline void add(const int &u,const int &v,const int &w){ e[k]=edge(v,w,head[u]); head[u]=k++; }
  17. }a,b;//a为正图,b为反图
  18. int f[maxn];
  19. bool vis[maxn];
  20. int n,m,s,t;
  21. struct set_elmt{
  22. int id,dis;
  23. set_elmt(){}
  24. set_elmt(const int &_dis,const int &_id){ id=_id,dis=_dis; }
  25. bool operator<(const set_elmt &x)const{ return dis>x.dis; }
  26. };//Dijkstra的优先级
  27. struct node{
  28. int id,dis;
  29. node(){}
  30. node(const int &_dis,const int &_id){ id=_id,dis=_dis; }
  31. bool operator<(const node &x)const{ return dis+f[id]>x.dis+f[x.id]; }
  32. };//A*的优先级
  33. inline int read(){
  34. register int x(0),f(1); register char c(getchar());
  35. while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
  36. while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
  37. return x*f;
  38. }
  39. inline void dijkstra(){
  40. memset(f,0x3f,sizeof f);
  41. priority_queue<set_elmt> q;
  42. q.push(set_elmt(0,t)),f[t]=0;
  43. while(q.size()){
  44. int u=q.top().id; q.pop();
  45. if(vis[u]) continue; vis[u]=true;
  46. for(register int i=b.head[u];~i;i=b.e[i].next){
  47. int v=b.e[i].to;
  48. if(f[v]>f[u]+b.e[i].dis) f[v]=f[u]+b.e[i].dis,q.push(set_elmt(f[v],v));
  49. }
  50. }
  51. }
  52. inline int astar(){
  53. int K=read()+(s==t);//特判(起点=终点)的情况
  54. priority_queue<node> q;
  55. q.push(node(0,s));
  56. while(q.size()){
  57. int u=q.top().id,w=q.top().dis; q.pop();
  58. if(u==t&&--K==0) return w;
  59. for(register int i=a.head[u];~i;i=a.e[i].next){
  60. int v=a.e[i].to;
  61. q.push(node(w+a.e[i].dis,v));
  62. }
  63. }
  64. return -1;
  65. }
  66. int main(){
  67. a.init(),b.init();
  68. n=read(),m=read();
  69. for(register int i=1;i<=m;i++){
  70. int u=read(),v=read(),w=read();
  71. a.add(u,v,w),b.add(v,u,w);
  72. }
  73. s=read(),t=read();
  74. dijkstra();
  75. printf("%d\n",astar());
  76. return 0;
  77. }

* A * 的复杂度看似和普通的Dijkstra+Heap求K短路一样,都是O(K * (N+M)logN),但实际上比它快很多。因为少搜了很多地方。

与图论的邂逅07:K短路的更多相关文章

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

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

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

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

  3. POJ--2449--Remmarguts&#39; Date【dijkstra_heap+A*】第K短路

    链接:http://poj.org/problem?id=2449 题意:告诉你有n个顶点,m条边.并把这些边的信息告诉你:起点.终点.权值.再告诉你s.t.k.需求出s到t的第k短路,没有则输出-1 ...

  4. POJ 2449 Remmarguts' Date ( 第 k 短路 && A*算法 )

    题意 : 给出一个有向图.求起点 s 到终点 t 的第 k 短路.不存在则输出 -1 #include<stdio.h> #include<string.h> #include ...

  5. 【模板篇】k短路 SDOI2010 魔法猪学院

    题目传送门 吐槽时间 题目分析 代码 题目の传送门 都成了一道模板题了OvO ============================================================= ...

  6. POJ 2449 Remmarguts' Date --K短路

    题意就是要求第K短的路的长度(S->T). 对于K短路,朴素想法是bfs,使用优先队列从源点s进行bfs,当第K次遍历到T的时候,就是K短路的长度. 但是这种方法效率太低,会扩展出很多状态,所以 ...

  7. POJ 2449Remmarguts' Date K短路模板 SPFA+A*

    K短路模板,A*+SPFA求K短路.A*中h的求法为在反图中做SPFA,求出到T点的最短路,极为估价函数h(这里不再是估价,而是准确值),然后跑A*,从S点开始(此时为最短路),然后把与S点能达到的点 ...

  8. BZOJ-1975 魔法猪学院 K短路 (A*+SPFA)

    1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec Memory Limit: 64 MB Submit: 1323 Solved: 433 [Submit][Statu ...

  9. 【POJ】2449 Remmarguts' Date(k短路)

    http://poj.org/problem?id=2449 不会.. 百度学习.. 恩. k短路不难理解的. 结合了a_star的思想.每动一次进行一次估价,然后找最小的(此时的最短路)然后累计到k ...

随机推荐

  1. selenium IDE使用-1

    selenium 硒 Mercury汞,外国人喜欢取这化学的名字 一.selenium概述 1.selenium是开源免费的,针对web应用程序功能自动化测试的工作. 2.做功能自动化的原因:回归测试 ...

  2. 深度学习炼丹术 —— Taoye不讲码德,又水文了,居然写感知器这么简单的内容

    手撕机器学习系列文章就暂时更新到此吧,目前已经完成了支持向量机SVM.决策树.KNN.贝叶斯.线性回归.Logistic回归,其他算法还请允许Taoye在这里先赊个账,后期有机会有时间再给大家补上. ...

  3. sqlmap进阶篇—POST注入三种方法

    测试是否存在post注入 第一种方法 直接加--form让它自动加载表单 第二种方法 把form表单里面提交的内容复制出来,放到data中跑 第三种方法 先用burp suite抓包,把包的内容存到本 ...

  4. 项目1_001_涉及知识点(Django任务追踪平台)

  5. Tensorflow环境配置&安装

    Tensorflow环境配置&安装 明知故犯,是不想有遗憾. 背景:Tensorflow 环境配置和安装. 一.安装 Anaconda 二.建立.激活.安装.验证.使用 Tensorflow ...

  6. 在Linux下面端口映射socat自动脚本

    这个sh脚本可以方面的端口映射,在使用本功能之前请确保socat已经放到了/usr/bin/socat #!/bin/bash cd `dirname $0` let listenport=`base ...

  7. 【升级版】如何使用阿里云云解析API实现动态域名解析,搭建私有服务器【含可执行文件和源码】

    原文地址:http://www.yxxrui.cn/article/179.shtml 未经许可请勿转载,如有疑问,请联系作者:yxxrui@163.com 我遇到的问题:公司的网络没有固定的公网IP ...

  8. [.NET] - 在Socket编程中遇到的问题总结

    问题1.无法访问已释放的对象. 对象名:"System.Net.Sockets.Socket" 产生这个scenario的原因是程序中的某个地方调用到了socket.close后, ...

  9. Go-Zero 短链项目 DevOps 实战,利用 Drone CI/CD 打通上云(Kubernetes)迭代流程

    Go-Zero 官方短链项目教程:快速构建高并发微服务 关于 go-zero,大家可以看文档.为少认为它是中国目前最好用的 golang 微服务框架. 完整的 Go-Zero ShortUrl Dev ...

  10. Linux 网络排错检查思路

    Linux 网络排错检查思路 graph TD A[当网络不通时] --> B{ping想要访问的地址,<br>如www.runoob.com} B --> |不通| C{pi ...