A*算法——第K短路
例题
题目描述
Bessie 来到一个小农场,有时她想回老家看看她的一位好友。她不想太早地回到老家,因为她喜欢途中的美丽风景。她决定选择K短路径,而不是最短路径。
农村有 R (1≤R≤100,000) 条单向的路,每条路连接 N (1≤N≤10000) 个结点中的两个。结点的编号是 1..N。Bessie 从结点 1出发,她的朋友(目的地)在结点 N。
同一个点可以多次经过。K短路的定义:假设从1出发,有M条长度不同的路径可以到达点N,则K短路就是这M条路径中第K小的路径长度。
输入格式
Line 1: 三个用空格分隔的整数 N,R,K((1≤n≤10000,1≤R≤100000,1≤K≤10000)
Lines 2..R+1: 每行包含三个用空格分隔的整数x,y,len(1≤x,y≤n,1≤len≤10000),表示x到y有一条长度为len的单向道路。
输出格式
输出包括一行,一个整数,第K短路的长度。
样例输入
4 4 2
1 2 100
2 4 200
2 3 250
3 4 100
样例输出
450
做法
考虑用A*算法。
我们知道A*算法有个性质:
设h(i)表示从i到终点的估计距离,设h*(i)表示i到终点的实际距离
1、当h(i) < h*(i)时,程序慢,但是保证找到最优解
2、当h(i) = h*(i)时,程序快,并且保证找到最优解
3、当h(i) > h*(i)时,程序快,但是不保证找到最优解
所以,若有元素t在堆顶弹出,若其为终点,且是第K次出堆,则答案为它走过的距离(t.g)
所以,首先我们预处理出h(i)。怎么求?我们可以考虑以上第二种方案。
因为我们可以先将所有的边的方向反过来,以N为起点,求出每一个点到N的最短路径。
最短路径都会吧?跑一遍SPFA(dijsktra没试过)。
h(i)为i到N的最短路径。
接下来开始A*!开一个堆,每次取出f(1到N估计总距离,f(i)=g(i)+h(i))最小的,然后往与它相连的点拓展。弹出后可以再进堆。若弹出的点为终点且是第K次出堆,则输出答案。
有一种坑了我很久的情况:当两条路径一样时,就当做一条看,加特判就行了。
但是不要乱加特判,要看题目,知道它要我们求什么。
代码实现(C++)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,r,k;//如题
struct Edge
{
int x,y,len;
Edge* las;//记录上一个和此次的x一样的边
} e1[100001],e2[100001];//e1是正向的,e2是反向的(前向星)
Edge *last1[10001],*last2[10001];//last[i]表示x为i的最后一条边
int h[10001];//见“做法”
const int SIZE=1000000;
int que[SIZE];
bool in_que[10001];
inline void spfa(int);
struct Node
{
int n,g,f; //n:在第n个点;g:已走g的路径;f:估计距离
} heap[SIZE];//堆
bool cmp(const Node& a,const Node& b)//比较函数
{
return a.f>b.f;
}
inline void A_star(int,int);
int main()
{
scanf("%d%d%d",&n,&r,&k);
int i,j=0,x,y,len;
for (i=1;i<=r;i++)
{
scanf("%d%d%d",&x,&y,&len);
while(getchar()!='\n');//这句话是因为数据有问题才加上去的,不用管
j++;
e1[j]={x,y,len,last1[x]};//新增一条边
last1[x]=e1+j;
e2[j]={y,x,len,last2[y]};
last2[y]=e2+j;
}
spfa(n);
A_star(1,n);
}
inline void spfa(int u)
{
memset(h,127,sizeof h);
h[u]=0;
int head=0,tail=1;
Edge* to;
que[1]=u;
in_que[u]=1;
do
{
if (++head==SIZE)
head=0;
for (to=last2[que[head]];to;to=to->las)
{
if (h[to->x]+to->len>=h[to->y])
continue;
h[to->y]=h[to->x]+to->len;
if (in_que[to->y])
continue;
if (++tail==SIZE)
tail=0;
que[tail]=to->y;
in_que[to->y]=1;
}
in_que[que[head]]=0;
}
while (head!=tail);
}
inline void A_star(int u,int v)
{
int nh=1,cnt=0,ans;
Edge* to;
*heap={u,0,h[u]};
while (nh)
{
if (heap->n==v && heap->g!=ans)//特判相等的情况
{
ans=heap->g;
if (++cnt==k)
{
printf("%d\n",heap->g);
return;
}
}
for (to=last1[heap->n];to;to=to->las)
{
heap[nh].n=to->y;
heap[nh].g=heap->g+to->len;
heap[nh].f=heap[nh].g+h[to->y];
nh++;
push_heap(heap,heap+nh,cmp);//加入堆
}
pop_heap(heap,heap+nh,cmp);
nh--;//弹出堆
}
}
A*算法——第K短路的更多相关文章
- bellman-ford算法求K短路O(n*m),以及判负环O(n*m)
#include<iostream> #include<algorithm> #include<cstring> using namespace std; cons ...
- 图论(A*算法,K短路) :POJ 2449 Remmarguts' Date
Remmarguts' Date Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 25216 Accepted: 6882 ...
- POJ2449-A*算法-第k短路
(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦 题意:传送门 原题目描述在最下面. 给你一个有向图,求指定节点间的第k短路. 思路: 先反向跑出从终点开始的到每个节点的最短距离 ...
- A*算法求K短路模板 POJ 2449
#include<cstdio> #include<queue> #include<cstring> using namespace std; const int ...
- k短路算法
k短路算法 求解k短路用到了A* 算法,A* ( A star )算法,又称启发式搜索算法,与之相对的,dfs与bfs都成为盲目型搜索:即为带有估价函数的优先队列BFS称为A*算法. 该算法的核心思想 ...
- bzoj 1975 [Sdoi2010]魔法猪学院(k短路)
题目描述 iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的学习之后,iPig对猪世界的世界本原有了很多的了解:众所周知,世界是由元素构成的:元素与 ...
- k短路模板 POJ2449
采用A*算法的k短路模板 #include <iostream> #include <cstdio> #include <cstring> #include < ...
- 【k短路&A*算法】BZOJ1975: [Sdoi2010]魔法猪学院
Description 找出1~k短路的长度. Solution k短路的求解要用到A*算法 A*算法的启发式函数f(n)=g(n)+h(n) g(n)是状态空间中搜索到n所花的实际代价 h(n) ...
- K短路 (A*算法) [Usaco2008 Mar]牛跑步&[Sdoi2010]魔法猪学院
A*属于搜索的一种,启发式搜索,即:每次搜索时加一个估价函数 这个算法可以用来解决K短路问题,常用的估价函数是:已经走过的距离+期望上最短的距离 通常和Dijkstra一起解决K短路 BZOJ1598 ...
随机推荐
- 在Debian中安装VNC Server
大部分情况下我们用ssh就可以登录linux服务器了.但有时候我们的程序需要在图形界面下运行,这时我们就要用到vnc server这个软件了. 在Debian下安装vnc server很简单的,只要几 ...
- 20140331 HOG代码调试 Boost库安装
1.CUDAHOG代码调试 错误1: 错误提示:(main.obj : error LNK2019: 无法解析的外部符号 "public: __thiscall cudaHOG::cudaH ...
- 用mapreduce实现将mysql数据导出到HDFS上
因为业务需要,需要将一批mysql数据导入到HBASE,现在先将数据从Mysql导出到HDFS. 版本:hadoop CDH4.5,Hbase-0.946 1.实体类 YqBean 是我的实体类,请根 ...
- Intellij IDEA 撸码最头大的问题。。
想栈长我当初从 Eclipse 转用 IDEA 真是纠结,放弃然后尝试了N次,不过现在已经算是转型成功了,可以完全脱离 Eclipse 撸码了,虽然说我现在真的撸得非常少了.. 说到 IDEA 的痛点 ...
- python中面向对象
一.Python经典类与新类 经典类:如果没有直接或间接的子类化一个对象,也就是说如果没有指定一个父类,或者是如果子类化的基本类没有父类,那么就定义了经典类: class classics: 'def ...
- uoj33 【UR #2】树上GCD
题目 大致是长剖+\(\rm dsu\ on\ tree\)的思想 先做一个转化,改为对于\(i\in[1,n-1]\)求出有多少个\(f(u,v)\)满足\(i|f(u,v)\),这样我们最后再做一 ...
- [MtOI2019]幽灵乐团
题目 一个很暴力的辣鸡做法 考虑到两个数的\(\gcd\)是所有质数次幂取\(\min\),两个数的\(\rm lcm\)是所有质数次幂取\(\max\),于是最后的答案一定是\(\prod p_i^ ...
- sort()和优先队列的总结
一.关于sort函数 sort()排序函数默认是从小到大, a={5,3,2,1,6 }; sort(a,a+n); //输出是1 2 3 5 6 这里如果要从到小排序,则有两种方式可以满足 (1) ...
- 无LoadLibrary获取指定模块基址
实际上,这块可以写成汇编,然后做远程注入用 方法 1.通过fs:[30h]获取当前进程的_PEB结构 2.通过_PEB的Ldr成员获取_PEB_LDR_DATA结构 3.通过_PEB_LDR_DATA ...
- vue better-scroll 下拉上拉,加载刷新
_initScroll(){ this.$nextTick(() => { if (!this.scroll) { ...