A*算法的认识与求第K短路模板
现在来解决A*求K短路问题
在一个有权图中,从起点到终点最短的路径成为最短路,第2短的路成为次短路,第3短的路成为第3短路,依此类推,第k短的路成为第k短路。那么,第k短路怎么求呢?
对于第k短路,可以想到的一个比较朴素的算法就是广度优先搜索,使用优先队列从源点s进行广搜,当第k次搜索到终点t时,所的长度即所求但是这种方法在运行过程中会产生特别多的状态,当图比较简单、k比较小时,可以一试,但是当k较大或者图中点数较多时,会面临爆栈的危险。目前使用比较多的算法是单源最短路配合A*。A*是搜索中比较高级的方式,A*算法结合了启发式方法(这种方法通过充分利用图给出的信息来动态的作出决定而使搜索次数大大降低)和形式化方法(这种方法不利用图给出的信息,而仅通过数学的形式分析,如Dijkstra算法)。它通过一个估价函数f(h)来估计图中的当前点p到终点的距离,并由此决定它的搜索方向,当这条路径失败时,它会尝试其他路径。对于A*,估价函数=当前值+当前位置到终点的距离,即f(p)=g(p)+h(p),每次扩展估价函数值最小的一个。对于第k短路算法来说,g(p)为从源点s到当前点p所走的路径长度,h(p)为从当前点p到终点t的最短路,因此f(p)的意义就是从s按照当前路径经过p点后到达t的总距离。也就是每次扩展都是有方向的,这样无论对提高出解的速度还是降低扩展的状态数目都是有好处的。为了加快计算,h(p)需要在搜索之前进行预处理,只要将原图的所有边反向,再从终点t做一次单源最短路即可得到h(p)。单源最短路求法有Dijkstra,Bellman-Ford,SPFA等。
具体步奏:
这里我们使用链式前向星来存储如图,由于需要预处理所有点到终点的最短路,就需要将图G中所有边反向得到图G',再从终点t做一次单源最短路,所以实际上就是两张图。
(1)将有向图的所有边反向(无向图可以省略此步),以原图终点t为源点做一次单源最短路,结果记入数组dis[i]中,dis[i]即为原图中点i到点t的最短距离。这里的dis[i]即上述的h(p);
(2)新建一个优先队列,将源点s加入到队列中;
(3)从优先队列中弹出f(p)最小的点p(这里如果存在f(p)相等的点,则弹出g(p)最小的点),如果点p就是终点t,则计算t出队列的次数,如果当前为t的第k次出队,则当前路径长度就是s到t的第k短路,算法结束;否则遍历与p相连的所有的边,将扩展出的到p的邻接点信息加入到优先队列。
值得注意的是,当s==t时需要计算(k+1)短路,因为s到t这条距离为0的路不能算在这k短路中,这时只需将k自增1后再求第k短路即可。
现在来实战下:
POJ 2449 Remmarguts' Date ( 第 k 短路 && A*算法 )
题意 : 给出一个有向图、求起点 s 到终点 t 的第 k 短路、不存在则输出 -1
- #include<stdio.h>
- #include<string.h>
- #include<queue>
- #include<algorithm>
- using namespace std;
- const int INF = 0x3f3f3f3f;
- const int maxn = ;
- const int maxm = ;
- struct EDGE{ int v, nxt, w; };
- struct NODE{
- int pos, Cost, F;
- bool operator < (const NODE & rhs) const {//重载的时候注意符号
- if(this->F == rhs.F) return this->Cost > rhs.Cost;
- return this->F > rhs.F;
- };
- };
- EDGE Edge[maxm];
- EDGE REdge[maxm];
- int Head[maxn], RHead[maxn];
- int cnt, Rcnt;
- int N;
- void init()
- {
- memset(Head, -, sizeof(Head));
- memset(RHead, -, sizeof(RHead));
- cnt = Rcnt = ;
- }
- void AddEdge(int from, int to, int weight)
- {
- Edge[cnt].w = weight;
- Edge[cnt].v = to;
- Edge[cnt].nxt = Head[from];
- Head[from] = cnt++;
- }
- void AddREdge(int from, int to, int weight)
- {
- REdge[Rcnt].w = weight;
- REdge[Rcnt].v = to;
- REdge[Rcnt].nxt = RHead[from];
- RHead[from] = Rcnt++;
- }
- int vis[maxn];
- int H[maxn];
- void SPFA(int st)
- {
- queue<int> que;
- memset(H, INF, sizeof(H));
- memset(vis, , sizeof(vis));
- H[st] = ;
- que.push(st);
- while(!que.empty()){
- int cur = que.front(); que.pop();
- vis[cur] = ;
- for(int i=RHead[cur]; i!=-; i=REdge[i].nxt) {
- int v = REdge[i].v;
- if(H[v] > H[cur] + REdge[i].w) {
- H[v] = H[cur] + REdge[i].w;
- if(!vis[v]) {
- vis[v] = ;
- que.push(v);
- }
- }
- }
- }
- }
- int A_Star(int s, int t, int k)
- {
- if(s == t) k++;
- if(H[s]==INF) return -;
- priority_queue<NODE> que;
- NODE cur, into;
- cur.pos = s;
- cur.Cost = ;
- cur.F = H[s];
- que.push(cur);
- int CNT = ;
- while(!que.empty()){
- cur = que.top();
- que.pop();
- if(cur.pos == t) CNT++;
- if(CNT == k) return cur.Cost;
- for(int i=Head[cur.pos]; i!=-; i=Edge[i].nxt){
- into.Cost = cur.Cost+Edge[i].w;
- into.F = cur.Cost+Edge[i].w+H[Edge[i].v];
- into.pos = Edge[i].v;
- que.push(into);
- }
- }return -;
- }
- int main(void)
- {
- int M, K, S, des;
- while(~scanf("%d %d", &N, &M)){
- init();
- int from, to, weight;
- while(M--){
- scanf("%d %d %d",&from, &to, &weight);
- AddEdge(from, to, weight);
- AddREdge(to, from, weight);//建反向边
- }
- scanf("%d %d %d", &S, &des, &K);
- SPFA(des);//求其他点到终点的最短路,作为H值
- printf("%d\n", A_Star(S,des,K));
- }
- return ;
- }
A*算法的认识与求第K短路模板的更多相关文章
- ACM-ICPC 2018 沈阳赛区网络预赛 D. Made In Heaven(第k短路模板)
求第k短路模板 先逆向求每个点到终点的距离,再用dij算法,不会超时(虽然还没搞明白为啥... #include<iostream> #include<cstdio> #inc ...
- poj 2449(A*求第K短路)
题目链接:http://poj.org/problem?id=2449 思路:我们可以定义g[x]为源点到当前点的距离,h[x]为当前点到目标节点的最短距离,显然有h[x]<=h*[x](h*[ ...
- [poj2449]Remmarguts' Date(K短路模板题,A*算法)
解题关键:k短路模板题,A*算法解决. #include<cstdio> #include<cstring> #include<algorithm> #includ ...
- POJ 2449Remmarguts' Date K短路模板 SPFA+A*
K短路模板,A*+SPFA求K短路.A*中h的求法为在反图中做SPFA,求出到T点的最短路,极为估价函数h(这里不再是估价,而是准确值),然后跑A*,从S点开始(此时为最短路),然后把与S点能达到的点 ...
- k短路模板 POJ2449
采用A*算法的k短路模板 #include <iostream> #include <cstdio> #include <cstring> #include < ...
- poj 2499第K短路模板
第k*短路模板(单项边) #include <iostream> #include <cstdio> #include <algorithm> #include & ...
- K短路模板POJ 2449 Remmarguts' Date
Time Limit: 4000MS Memory Limit: 65536K Total Submissions:32863 Accepted: 8953 Description &qu ...
- A* 算法求第 K 短路
一种具有 \(f(n)=g(n)+h(n)\) 策略的启发式算法能成为 A* 算法的充分条件是: 搜索树上存在着从起始点到终了点的最优路径. 问题域是有限的. 所有结点的子结点的搜索代价值 \(> ...
- aStar算法求第k短路
A*的概念主意在于估计函数,f(n)=g(n)+h(n),f(n)是估计函数,g(n)是n节点的当前代价,h(n)是n节点的估计代价:而实际中,存在最优的估计函数f'(n)=g'(n)+h'(n),那 ...
随机推荐
- 《Javascript高级程序设计》阅读记录(一):第二、三章
<Javascript高级程序设计>阅读记录(一) 这个系列,我会把阅读<Javascript高级程序设计>之后,感觉讲的比较深入,而且实际使用价值较大的内容记录下来,并且注释 ...
- html事件绑定总结以及window.onload和document.body.onload事件
//1 document.onkeydown如果多次监听同样的事件,那么前面的监听函数都会被最后一次的监听函数所覆盖. //如下所示: document.onkeydown = function(ev ...
- Maven(5)-优化和重构POM
本文主要介绍如何优化pom,杜绝重复(DRY). 1)模块重复依赖: 2)坐标版本号重复: 3)兄弟依赖 一.项目骨架 上图说明: multi-module-project是一个有多个模块构成的项目, ...
- nginx中给目录增加密码保护实现程序
一款nginx中给目录增加密码保护实现程序,可以有效的保护一些目录不被访问,有需要的朋友可参考一下. 了防止一些可能出现存在漏洞的后台脚本暴露,使用验证的方式保护这些文件所在的目录 使用apache的 ...
- Go中使用动态库C/C++库
转自:http://studygolang.com/articles/1441 最近需要做一些在go中使用动态C++库的工作,经常碰到找不到动态库路径这种情况,所以就花点时间,专门做一下实验来了解Go ...
- HttpApplication 对象的创建过程及HttpModule过滤器的内部实现过程
最近通过Reflector学习了一下asp.net内部的原理,做做笔记,方便以后查阅. 先看下HttpApplication 对象的创建过程 从IHttpHandler applicationInst ...
- linux 防暴力破解
#!/bin/bash SCANIP=`grep "Failed" /var/log/secure* | awk '{print $(NF-3)}'| sort |uniq -c ...
- 关于javaScript事件委托的那些事
今天是第一次写稿,还是有那么一丢丢小鸡冻...回归正题啦... 关于javaScript事件委托不得不说的那些事,为什么要使用事件委托? 我们可以这么说,假设老板要分配一项任务,首先要秘书叫A君来到办 ...
- [ural1132]Square Root(cipolla算法)
题意:求${x^2} \equiv n\bmod p$ 解题关键: 定理:若$a$满足$w = {a^2} - n$是模$p$的二次非剩余,即,${x^2} = w\bmod p$无解,则${(a + ...
- CSS样式基础:
CSS:外部文件导入 <link rel="stylesheet" type="text/css" href="./style.css&quo ...