题意:

给定一张N个点,M条边的有向图,求从起点到终点T的第K短路的长度。

思路:

求第K短路,我们先回忆一下Dijkstra求最短路的方法。

每次松弛了一个节点,则将该节点放入优先队列,然后在取优先队列的第一个点,即源点到该点距离最短的点,再用该点去松弛其他的点。最终求出的距离就是单源最短距离。

换句话说,就是用优先队列bfs对整张图进行遍历,当一个点被第一次取出时,此时的距离便是该点的最短距离。

由此,我们便得知了求第K短路的方法。即对于任意顶点 i ,当顶点 i 被第K次取出时,此时的距离便是该点的第K短路。

但是,如果直接用优先队列的bfs去求第K短路,无疑会造成大量的冗余搜索。因此我们需要用A*算法,即启发式算法进行优化。

启发式算法的核心:

1.设立一个估价函数,对于每一个状态,估价函数的值就是该状态到目标状态所需的花费。注意这个花费必须小于真实花费,否则程序会出错。

2.对每一次搜索到的状态,我们定义该状态的值为“该状态的花费”+“该状态到目标状态所需的值”,即估价函数在该状态下的值。

3.然后我们每次取出状态值最小的点进行bfs,即可优化搜索。

由此,A*,即是改变bfs的搜索方向,使得我们更快地搜到目标值。

我们再回到本题,在该题中,估价函数应该是该点到目标点的距离,此时估价花费 <= 真实花费,因此可行。

我们定义每个点的值为当前到该点的距离 + 该点到目标点的距离,然后再进行bfs优先队列搜索,即为A*算法在本题的应用。

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#define rep(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
const int M = 1e5+100;
const int N = 2000;
const int inf = 0x3f3f3f3f;int n,m,s,t,k;
struct Edge{int to,next,w;
}e[M],ef[M];
int head[N],headf[N],tot,totf;
int dis[N],book[N],dist[N];
struct Po{int id;   //到达哪一个点int fw; //到该点已经走过的距离int w; //到该点已经走过的距离+该点距离终点的距离
}tmp;bool operator < (Po x,Po y) //优先队列只能重载 <
{return x.w>y.w; //如果放在结构体内重载,需要加const
}
void init()
{tot = 1; totf = 1;memset(head,0,sizeof head);memset(headf,0,sizeof headf);
}void add(int x,int y,int w)
{e[++tot].to = y; e[tot].next = head[x]; head[x] = tot; e[tot].w = w;
}void addf(int x,int y,int w)
{ef[++totf].to = y; ef[totf].next = headf[x]; headf[x] = totf; ef[totf].w = w;
}void spfa(int x)
{queue<int> q;memset(book,0,sizeof book);rep(i,1,n) dis[i] = inf;while(!q.empty()) q.pop();q.push(x);book[x] = 1;dis[x] = 0;while(!q.empty()){int p = q.front();for(int i = headf[p]; i ; i = ef[i].next){if(dis[ef[i].to] > dis[p]+ef[i].w){dis[ef[i].to] = dis[p]+ef[i].w;if(book[ef[i].to] == 0){q.push(ef[i].to);book[ef[i].to] = 1;}}}book[p] = 0;q.pop();}
}int bfs()
{if(dis[s] == inf) return -1; //如果不加这句话,就是wa,确保连通性int val = 0;priority_queue<Po> q;while(!q.empty()) q.pop();tmp.fw = 0;    //走到id这个点目前所需要的距离tmp.id = s;tmp.w = tmp.fw+dis[tmp.id];q.push(tmp);if(t==s)k++;  //这里也是一个大坑点while(!q.empty()){Po p = q.top();q.pop();   //优先队列,必须在push之前就pop,不然队列顶的那个点会被调到底下去int id = p.id;  //p所在的点if(id == t) val++;if(val == k) return p.fw;    //求第k短路for(int i = head[id]; i ; i = e[i].next)   //加入新边{tmp.fw = p.fw+e[i].w;tmp.id = e[i].to;tmp.w = tmp.fw+dis[tmp.id];   //此处为估价函数q.push(tmp);}}if(val!=k){return -1;}
}int main()
{while(~scanf("%d%d",&n,&m)){init();rep(i,1,m){int x,y,z;scanf("%d%d%d",&x,&y,&z);add(x,y,z);addf(y,x,z);}scanf("%d%d%d",&s,&t,&k);spfa(t);printf("%d\n",bfs());}return 0;
}/*
2 10
1 2 42
1 2 1
1 1 79
2 2 65
2 2 82
1 2 92
2 1 28
2 1 5
2 1 93
2 1 17
1 2 1000
*/

【POJ 2449】第K短路【A*算法】相关推荐

  1. poj 2449 Remmarguts' Date 启发式搜索 A*算法

    做这个题算是学了学spfa算法,一开始感觉spfa和dij好像:dij找最小点松弛,spfa就是一个一个的松弛,松到不能松. 求S到T的第K短路 思路:这个算法的思路是从源点S优雅的暴力跑bfs,用优 ...

  2. 第k短路 (A*算法)

    A*算法: A*,启发式搜索,是一种较为有效的搜索方法. 我们在搜索的时候,很多时候在当前状态,已经不是最优解了,但是我们却继续求解:这个就是暴力搜索浪费时间的原因. 我们在有些时候,往往可以根据一些 ...

  3. 第K短路(A*算法)

    给定一张 NN 个点(编号 1,2-N),MM 条边的有向图,求从起点 S 到终点 T 的第 K 短路的长度,路径允许重复经过点或边. 注意: 每条最短路中至少要包含一条边. 输入格式 第一行包含两个 ...

  4. 第k短路----A*算法

    题目链接 大佬题解:https://www.acwing.com/solution/content/21233/ #include <iostream> #include <cstr ...

  5. A*算法的认识与求第K短路模板

    现在来了解A*算法是什么 现在来解决A*求K短路问题 在一个有权图中,从起点到终点最短的路径成为最短路,第2短的路成为次短路,第3短的路成为第3短路,依此类推,第k短的路成为第k短路.那么,第k短路怎 ...

  6. ACM-ICPC 2018 沈阳赛区网络预赛 D. Made In Heaven (K短路算法模板)

    题意 : 求第k短路的权值是否超过T(权值) 解法: 网上随便找的一个求K短路的算法模板套弄一下即可 (模板要好,不然邻接表存图会TLE , 网上换了两个模板才AC的) AC代码: #include& ...

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

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

  8. k短路 k shortest path 入门

    K短路求解算法常用的有djstra + A* 和 Yen算法.本文主要讲解djstra + A* 先了解下A*中的估值函数 f(n)=g(n)+h(n) f ( n ) = g ( n ) + h ( ...

  9. [jzoj1163]第k短路

    Description Bessie 来到一个小农场,有时她想回老家看看她的一位好友.她不想太早地回到老家,因为她喜欢途中的美丽风景.她决定选择K短路径,而不是最短路径. 农村有 R (1≤R≤100 ...

  10. POJ 2449 Remmarguts' Date(k短路模板)

    link:https://vjudge.net/problem/POJ-2449 前面输入与大多最短路题相同 最后一行输入s,t,k 求从s到t的第K短路 wiki link: https://en. ...

最新文章

  1. 一篇综述带你全面了解迁移学习的领域泛化(Domain Generalization)
  2. 脑电信号特征提取常用算法(共空间模式CSP、小波变换DWT、功率谱密度PSD、AR模型)
  3. android surfaceflinger 老罗,「Android」SurfaceFlinger分析
  4. 10.python网络编程(socket server 实现并发 part 2)
  5. PAT: gets’ was not declared in this scope gets(s)
  6. 提取pdf文件文本:pdfparser与xpdf具体操作
  7. 《麦肯锡方法》读书笔记15
  8. C#中使用SHFileOperation调用Windows的复制文件对话框
  9. 基于3线spi通信的oled(cubemx图形化编程软件)
  10. xp重启计算机的快捷键,xp电脑关机重启快捷键如何使用
  11. android显卡效果吗,安卓模拟器显卡渲染模式中DirectX和OpenGL两个有什么区别?
  12. Spring框架(容器)--简介(实现原理、核心模块、组成部分)
  13. 分析linux启动内核源码
  14. Android Audio(七)—— AudioFocus(duck)
  15. 如何通过脚本开发Android
  16. 垃圾回收与垃圾收集算法
  17. 瑞波加入超级账本区块链联盟
  18. android逆向,必会的命令
  19. 使用Bento4在ubuntu16.04切片视频并生成MPD
  20. 14、ADS使用记录之功率放大器设计

热门文章

  1. 为了方便远程登录写的简单expect脚本
  2. 使用DPM2007来保护企业数据
  3. mybatis-generator逆向工程生成boolean字段解决办法
  4. 安徽工业大学java实验报告_安徽工业大学java实验报告.doc
  5. 米莱迪机器人加物理攻击_自拍、航拍、运动拍“ALL IN ONE”,臻迪PowerEgg X开启全新未来...
  6. oracle分区表 mysql_Oracle分区表的使用和管理
  7. c++单例模式Singleton Pattern
  8. mysql sql model设置_操作mysql model
  9. siteservercms 缺点_SiteServer CMS 术语大全
  10. C/C++[指针/引用]