题目链接:点击查看

题目大意:给出一个有向图,求第k短路

题目分析:偷学了一波A*,本来以为是多难的算法,其实就是bfs+优先队列的升级版,之前看的那些博客写的都太深奥了,以至于看了一半啥都没看懂然后就被吓跑了,这里放一波zx学长PPT上的描述,我感觉简洁精炼,几句话就把这个算法的核心描述清楚了:

  • A * 算法的实现,A * =优先队列BFS+估价函数。
  • 回顾优先队列bfs:优先队列BFS算法维护了一个优先队列,不断从堆中取出当前代价最小的状态进行扩展。每个状态第一次从堆中取出时,就得到了从初态到该状态的最小代价。
  • 局限:如果给定一个目标状态,需要求出从初态到目标状态的最小代价,那么优先队列BFS这个优先策略是不完善的。一个状态当前代价小,只能说明从起始状态到该状态代价小,而在未来的搜索中从该状态到目标状态的花费可能会很大。导致有一部分很晚才能得到扩展。
  • 为了提高搜索效率,我们很自然的想到,可以对未来可能产生的代价进行预估。
  • 详细的讲:我们设计一个估价函数,以任意状态为输入,计算出从该状态到目标状态所需代价的估计值。在搜索中,仍然维护一个堆,不断从堆中取出 当前代价+未来估价 最小的状态进行扩展
  • 为了保证第一次从堆中取出目标状态时得到的就是最优解,我们设计的估价函数需要满足一个基本准则:估价函数的估值不能大于未来实际代价,估价比实际代价更优。
  • 这种带有估价函数的优先队列BFS就称为A * 算法。只要保证对于任意状态state,都有f(state)≤g(state),A * 算法就一定能在目标状态第一次从堆中被取出时得到最优解,并且在搜索过程中每个状态只需要被扩展一次(之后再被取出就可以直接忽略)。估价f(state)越准确,越接近g(state),A * 算法的效率就越高。如果估价始终为0,就等价于普通优先队列BFS。
  • A * 算法提高搜索效率的关键,就在于能否设计出一个优秀的估价函数。估价函数在满足上述设计准则的前提下,含应该尽可能反映未来实际代价的变化趋势和相对大小关系,这样搜索才会较快的逼近最优解
  • 估价函数的设计准则:
  • 估值f(state)≤未来实际代价g(state)

那么再回到这个题目上面,我们只需要设计出估价函数即可,这个题目的权值是距离,当我们到达一个点后,利用bfs的状态转移可以很容易的知道从起点到当前点的距离,那怎么知道当前点到终点的距离呢?我们可以一开始从终点跑一遍迪杰斯特拉或者spfa,这样就能轻松表达出估价函数了,有了估价函数后,我们在优先队列+bfs的基础上,更改排序函数的机制为估价函数,然后给我们的bfs函数改个名字,就变成A*算法了

有一个坑点需要注意一下,当终点和起点重合的时候,我们需要让k++,以避免出现让起点直接到达终点的现象发生

代码,模板题:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e3+100;int d[N];bool vis[N];struct Node
{int to,w;Node(int TO,int W){to=TO;w=W;}Node(){}bool operator<(const Node& a)const{return w+d[to]>a.w+d[a.to];}
};vector<Node>node1[N],node2[N];//1:正向边 2:反向边 void spfa(int x)
{memset(vis,false,sizeof(vis));memset(d,inf,sizeof(d));queue<int>q;q.push(x);d[x]=0;vis[x]=true;while(!q.empty()){int from=q.front();q.pop();vis[from]=false;for(int i=0;i<node2[from].size();i++){int to=node2[from][i].to;int w=node2[from][i].w;if(d[to]>d[from]+w){d[to]=d[from]+w;if(!vis[to]){vis[to]=true;q.push(to);}}}}
}int A_star(int start,int end,int k)
{priority_queue<Node>q;q.push(Node(start,0));while(!q.empty()){Node cur=q.top();q.pop();if(cur.to==end){k--;if(!k)return cur.w;}for(int i=0;i<node1[cur.to].size();i++){int to=node1[cur.to][i].to;int w=node1[cur.to][i].w;q.push(Node(to,cur.w+w));}}return -1;
}int main()
{
//  freopen("input.txt","r",stdin);int n,m;while(scanf("%d%d",&n,&m)!=EOF){for(int i=1;i<=n;i++){node1[i].clear();node2[i].clear();}while(m--){int u,v,w;scanf("%d%d%d",&u,&v,&w);node1[u].push_back(Node(v,w));node2[v].push_back(Node(u,w));}int s,e,k;scanf("%d%d%d",&s,&e,&k);spfa(e);if(d[s]==inf){printf("-1\n");continue;}if(s==e)//特判一下,坑 k++;printf("%d\n",A_star(s,e,k));}return 0;
}

POJ - 2449 Remmarguts' Date(第k短路:spfa+A*)相关推荐

  1. POJ 2449 Remmarguts' Date [第k短路]

    Remmarguts' Date Time Limit: 4000MS Memory Limit: 65536KB 64bit IO Format: %lld & %llu Descripti ...

  2. POJ 2449 Remmarguts' Date(第K短路 + A* + 最短路)题解

    题意:找出第k短路,输出长度,没有输出-1 思路:这题可以用A*做.A*的原理是这样,我们用一个函数:f = g + h 来表示当前点的预期步数,f代表当前点的预期步数,g代表从起点走到当前的步数,h ...

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

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

  4. poj2449 Remmarguts' Date(第k短路问题)(A*+spfa/dijkstra)

    思路来源 https://blog.csdn.net/berrykanry/article/details/78345894(通俗易懂解释好评) https://www.cnblogs.com/yyf ...

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

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

  6. POJ 2449 Remmarguts' Date

    POJ_2449 一开始我的思路就是把图上每个点搞一个容量不小于K的最大堆和最小堆,最小堆用于取当前该节点的第某短路值,最大堆用来保存前K小的最短路. 最后为了每次能查询全局最小值,再把N个点放到一个 ...

  7. 【POJ】3255 Roadblocks(次短路+spfa)

    http://poj.org/problem?id=3255 同匈牙利游戏. 但是我发现了一个致命bug. 就是在匈牙利那篇,应该dis2单独if,而不是else if,因为dis2和dis1相对独立 ...

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

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

  9. Poj2449 Remmarguts' Date 【A*搜索】K短路

    http://poj.org/problem?id=2449 A*搜索求K短路. #include <cstdio> #include <cstring> #include & ...

最新文章

  1. LeetCode中等题之特殊等价字符串组
  2. 机器学习基础--基本术语
  3. 这样的烂代码,我实习的时候都写不出来!
  4. jemter编写Mysql脚本___传参
  5. linux deploy 版本,Linux Deploy
  6. DataGridView 单元格验证
  7. python实现RSA算法,对数据进行加密认证
  8. 【C语言】 删除一个字符串中重复的字符
  9. ARM全新Armv9架构:10年最大更新、增强AI和security能力
  10. Microsoft Visual Studio使用NodeJS
  11. 电子换向电动机行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
  12. 解决办法:nvidia-docker2 : 依赖: docker-ce (= 5:18.09.0~3-0~ubuntu-xenial)
  13. 淘宝手淘搜索怎么做?大神导航,一个神奇的网站,从此开启大神之路!
  14. [SUCTF 2018]GetShell
  15. uni-app设置屏幕亮度
  16. 2023昆明理工大学计算机考研信息汇总
  17. Revit模型轻量化方法
  18. python的镜像安装和设置
  19. 聚簇索引与非聚簇索引
  20. 心流_追求生命的意义

热门文章

  1. MyBatis 插件怎么编写和使用?原理是什么?
  2. 微服务网关路由过滤作用介绍
  3. 依赖注入_set方法注入_构造器注入
  4. 页面定时跳转(读秒)
  5. ServletContext_概述
  6. 常见问题_空指针异常
  7. SpringCloud版本定义说明
  8. SpringBoot_日志-指定日志文件和日志Profile功能
  9. Linux下Mysql设置外网可以访问
  10. webflux系列--reactor源码(二)