题目链接:http://poj.org/problem?id=2449

题目大意:

给出n个点,m条有向边,最后一行给出起点到终点的第k短路。求长度。

题解思路:

这是我第一道第k短路题以及A*算法的使用。

这是一篇A*算法讲的非常好的博客:https://blog.csdn.net/weixin_44489823/article/details/89382502

将A*运用到求第k短路上实际上与文章中的A*是有所不同的。但是精髓没有改变,精髓是寻路时,选择 f 值最小的点,用来避免寻找无用的路径。在A*算法中本应该对所经过的点进行标记,就像是bfs时对已经经过的点进行标记,但在第k短路中不可以,因为需要重复走各个需要走的点。那么在每次走到终点一定是当前一次的最短路,在下一次再次走到终点时,就是第2次最短路,以此类推,第k短路就是第k次到达终点时所走的总路程。

对于h评估函数,在第k短路是终点到各个点的距离,对原图建一个反向图,以终点为起边来跑一遍最短路即可得到h数组。

对于g函数,是所走过的距离,即原图起点到该点的距离。

代码如下:

 #include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
#define mem(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int MAXN = 1e3 + ;
const int MAXM = 1e5 + ;
const int inf = 0x3f3f3f3f; int n, m; //n个点 m条有向边
int head[MAXN], cnt, r_head[MAXN], r_cnt;
int vis[MAXN];
ll h[MAXN]; struct Edge
{
int to, next, w;
}e[MAXM], r_e[MAXM]; struct Node
{
int pot;
ll g, h;
bool operator < (const Node &a)const //优先选择f值小的点 A*算法精髓所在
{
return g + h > a.g + a.h;
}
}node; void add(int a, int b, int c)
{
cnt ++;
e[cnt].to = b;
e[cnt].next = head[a];
e[cnt].w = c;
head[a] = cnt;
} void r_add(int a, int b, int c) //反向边 与正向边的编号一致
{
r_cnt ++;
r_e[r_cnt].to = b;
r_e[r_cnt].next = r_head[a];
r_e[r_cnt].w = c;
r_head[a] = r_cnt;
} int spfa(int st, int ed) //反向图 跑 h 评估函数(在这里也就是终点到该点的最短距离) A*算法精髓
{
mem(h, inf), mem(vis, );
queue<int> Q;
while(!Q.empty()) Q.pop();
vis[st] = ;
h[st] = ;
Q.push(st);
while(!Q.empty())
{
int a = Q.front();
Q.pop();
vis[a] = ;
for(int i = r_head[a]; i != -; i = r_e[i].next)
{
int to = r_e[i].to;
if(h[to] > h[a] + r_e[i].w * 1ll)
{
h[to] = h[a] + r_e[i].w * 1ll;
if(!vis[to])
{
vis[to] = ;
Q.push(to);
}
}
}
}
return h[ed] != inf;
} ll A_star(int st, int ed, int k) //优先队列 优先选择f值小的点 跑正向图
{
int num = ;
priority_queue<Node> QQ;
while(!QQ.empty()) QQ.pop();
node.pot = st, node.g = , node.h = h[st];
QQ.push(node);
while(!QQ.empty())
{
Node a = QQ.top();
QQ.pop();
// printf("%d\n", a.pot);
if(a.pot == ed) //如果第k次找到终点 就得出了答案
{
num ++;
if(num == k)
return a.g + a.h;
}
for(int i = head[a.pot]; i != -; i = e[i].next)
{
int to = e[i].to;
node.pot = to;
node.g = a.g + e[i].w * 1ll;
node.h = h[to];
QQ.push(node);
}
}
return -;
} int main()
{
scanf("%d%d", &n, &m);
mem(head, -), cnt = ;
mem(r_head, -), r_cnt = ;
for(int i = ; i <= m; i ++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
r_add(b, a, c);
}
int a, b, k; //a 到 b 的第 k 短路
scanf("%d%d%d", &a, &b, &k);
if(a == b)
k ++;
if(!spfa(b, a))
printf("-1\n"); //若起点到终点本身就不连通 就不存在第k短路 输出-1
else
printf("%lld\n", A_star(a, b, k));
return ;
}

第k短路模板

POJ2449 【第k短路/A*】的更多相关文章

  1. poj2449 第k短路

    题目链接 学习博客:https://blog.csdn.net/Z_Mendez/article/details/47057461 k短路没有我想象的那么难,还是很容易理解的 求s点到t点的第k短路径 ...

  2. poj2449第K短路问题(A*算法)

    启发函数:f(x)=g(x)+h(x); g(x)表示初始点到x状态的代价,h(x)表示从x的状态到目标状态的代价的估计值(并不是真实的),实际最小代价<=h(x); 起点s,终点t,x.v=s ...

  3. POJ2449 (k短路)

    #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> # ...

  4. POJ2449 Remmarguts' Date 第K短路

    POJ2449 比较裸的K短路问题 K短路听起来高大上 实际思路并不复杂 首先对终点t到其他所有点求最短路 即为dist[] 然后由起点s 根据当前走过的距离+dist[]进行A*搜索 第k次到达t即 ...

  5. A*模板(求K短路)(POJ2449)

    A*是bfs的优化,IDA*是dfs的优化 A*算法: 为启发式算法中很重要的一种,被广泛应用在最优路径求解和一些策略设计的问题中.而A*算法最为核心的部分,就在于它的一个估值函数的设计上: f(n) ...

  6. k短路模板 POJ2449

    采用A*算法的k短路模板 #include <iostream> #include <cstdio> #include <cstring> #include < ...

  7. 第K短路模板【POJ2449 / 洛谷2483 / BZOJ1975 / HDU6181】

    1.到底如何求k短路的? 我们考虑,要求k短路,要先求出最短路/次短路/第三短路……/第(k-1)短路,然后访问到第k短路. 接下来的方法就是如此操作的. 2.f(x)的意义? 我们得到的f(x)更小 ...

  8. [poj2449]Remmarguts' Date(K短路模板题,A*算法)

    解题关键:k短路模板题,A*算法解决. #include<cstdio> #include<cstring> #include<algorithm> #includ ...

  9. POJ2449:K短路

    Remmarguts' Date Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 26355   Accepted: 7170 ...

  10. poj2449(k短路&A_star模板)

    题目链接:http://poj.org/problem?id=2449 题意:给出一个有向图,求s到t的第k短路: 思路:k短路模板题,可以用A_star模板过: 单源点最短路径+高级搜索A*;A*算 ...

随机推荐

  1. java重载和重写

    重载(Overloading) (1) 方法重载是让类以统一的方式处理不同类型数据的一种手段.多个同名函数同时存在,具有不同的参数个数/类型. 重载Overloading是一个类中多态性的一种表现. ...

  2. 斜率dp的模板总结

    #include<cstdio> #include<algorithm> using namespace std; long long sumt[40005],sum[4000 ...

  3. TensorFlow(十一):递归神经网络(RNN与LSTM)

    RNN RNN(Recurrent Neural Networks,循环神经网络)不仅会学习当前时刻的信息,也会依赖之前的序列信息.由于其特殊的网络模型结构解决了信息保存的问题.所以RNN对处理时间序 ...

  4. linux 搭建elk6.8.0集群并破解安装x-pack

    一.环境信息以及安装前准备 1.组件介绍 *Filebeat是一个日志文件托运工具,在你的服务器上安装客户端后,filebeat会监控日志目录或者指定的日志文件,追踪读取这些文件(追踪文件的变化,不停 ...

  5. linux中清理旧内核

    执行update的时候会自动升级内核,开机启动的时候会好多内核选项.所以我们要清理不需要内核. 查看当前系统使用的内核版本 uname -a Linux localhost.localdomain 3 ...

  6. WebSocket浅谈

    WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议. 在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速 ...

  7. Node.js 目录操作

    1.创建目录 mkdir 代码 demo1.js var fs = require('fs'); //创建目录 fs.mkdir('e:/nodeTest/dirTest',function(err) ...

  8. My algorithmic road

    序言 初窥门径 1 第一题 素数的烦恼 离开了家乡,你到达了数字之地,在这里数字2总感觉自己是自然数中最独特的一个,他只有一和它本身两个因数,为此它十分苦恼.为了不再寂寞,他建立了素数王国,他请求许多 ...

  9. C++ 中virtual 用法

    一.virtual 修饰基类中的函数,派生类重写该函数: #include using namespace std; class A{ public: virtual void display(){ ...

  10. openstack instance change storage dir

    在云计算openstack中以为新建的虚拟机都存放在/var/lib/nova/instances中,在新建虚拟机时内存当然不够用,所以可以将nova转移到新的存储位置 以下操作只在计算节点上进行 一 ...