与图论的邂逅07:K短路
在做最短路的题时我们不免会碰到许多求次短路的题,然而我们也能很快地想到解决的办法:
用dijkstra跑一遍最短路,当终点第二次被取出时就是次短路了。时间复杂度为O((N+M)logN)。实际上前面得乘个2.
那么根据OI的尿性,有了最优解问题,又有了次优解问题,接下来是什么?K优解!那么K短路怎么做?
仍然可以用上面的方法,用dijkstra不停地跑,直到终点被第k次取出时就是K短路。时间复杂度就是:O(K*(N+M)logN)。然而这种复杂度随便上网搜一道模板题都跑不过。
其实dijkstra可以看成加了优先队列的广度优先搜索。为了优化这种搜索,我们唯独可以在它的堆里面动点手脚。这时就要用到神奇的A*算法了。
根据设计估价函数的原则,其估计值f[x]不能大于其实际值,即无论K为多少时,f[x]都要小于等于x到终点的第K短路。通俗一点,设x到终点的所有path共同构成一个集合S:
\]
设x到终点的最短路为ShortestPath,上面的式子可以简化为:
\]
而这意味着我们直接令f[x]=ShortestPath就可以了!
所以我们首先预处理出所有点的预估值。具体操作是:建立反图,从终点开始跑出每个点的最短路的长度作为预估值。
然后我们每次只需要从堆里面取出dis[x]+f[x]最小的那个即可。当终点被第K次取出时就是K短路。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define maxn 1001
#define maxm 100001
using namespace std;
struct graph{
struct edge{
int to,dis,next;
edge(){}
edge(const int &_to,const int &_dis,const int &_next){ to=_to,dis=_dis,next=_next; }
}e[maxm];
int head[maxn],k;
inline void init(){ memset(head,-1,sizeof head); }
inline void add(const int &u,const int &v,const int &w){ e[k]=edge(v,w,head[u]); head[u]=k++; }
}a,b;//a为正图,b为反图
int f[maxn];
bool vis[maxn];
int n,m,s,t;
struct set_elmt{
int id,dis;
set_elmt(){}
set_elmt(const int &_dis,const int &_id){ id=_id,dis=_dis; }
bool operator<(const set_elmt &x)const{ return dis>x.dis; }
};//Dijkstra的优先级
struct node{
int id,dis;
node(){}
node(const int &_dis,const int &_id){ id=_id,dis=_dis; }
bool operator<(const node &x)const{ return dis+f[id]>x.dis+f[x.id]; }
};//A*的优先级
inline int read(){
register int x(0),f(1); register char c(getchar());
while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
inline void dijkstra(){
memset(f,0x3f,sizeof f);
priority_queue<set_elmt> q;
q.push(set_elmt(0,t)),f[t]=0;
while(q.size()){
int u=q.top().id; q.pop();
if(vis[u]) continue; vis[u]=true;
for(register int i=b.head[u];~i;i=b.e[i].next){
int v=b.e[i].to;
if(f[v]>f[u]+b.e[i].dis) f[v]=f[u]+b.e[i].dis,q.push(set_elmt(f[v],v));
}
}
}
inline int astar(){
int K=read()+(s==t);//特判(起点=终点)的情况
priority_queue<node> q;
q.push(node(0,s));
while(q.size()){
int u=q.top().id,w=q.top().dis; q.pop();
if(u==t&&--K==0) return w;
for(register int i=a.head[u];~i;i=a.e[i].next){
int v=a.e[i].to;
q.push(node(w+a.e[i].dis,v));
}
}
return -1;
}
int main(){
a.init(),b.init();
n=read(),m=read();
for(register int i=1;i<=m;i++){
int u=read(),v=read(),w=read();
a.add(u,v,w),b.add(v,u,w);
}
s=read(),t=read();
dijkstra();
printf("%d\n",astar());
return 0;
}
* A * 的复杂度看似和普通的Dijkstra+Heap求K短路一样,都是O(K * (N+M)logN),但实际上比它快很多。因为少搜了很多地方。
与图论的邂逅07:K短路的更多相关文章
- 图论(A*算法,K短路) :POJ 2449 Remmarguts' Date
Remmarguts' Date Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 25216 Accepted: 6882 ...
- 图论&搜索:K短路-启发式搜索
判断第k短路的权值是否小于T 直接把队友的代码拿过来了,一定很经典 #include <iostream> #include <queue> #include <cstr ...
- POJ--2449--Remmarguts' Date【dijkstra_heap+A*】第K短路
链接:http://poj.org/problem?id=2449 题意:告诉你有n个顶点,m条边.并把这些边的信息告诉你:起点.终点.权值.再告诉你s.t.k.需求出s到t的第k短路,没有则输出-1 ...
- POJ 2449 Remmarguts' Date ( 第 k 短路 && A*算法 )
题意 : 给出一个有向图.求起点 s 到终点 t 的第 k 短路.不存在则输出 -1 #include<stdio.h> #include<string.h> #include ...
- 【模板篇】k短路 SDOI2010 魔法猪学院
题目传送门 吐槽时间 题目分析 代码 题目の传送门 都成了一道模板题了OvO ============================================================= ...
- POJ 2449 Remmarguts' Date --K短路
题意就是要求第K短的路的长度(S->T). 对于K短路,朴素想法是bfs,使用优先队列从源点s进行bfs,当第K次遍历到T的时候,就是K短路的长度. 但是这种方法效率太低,会扩展出很多状态,所以 ...
- POJ 2449Remmarguts' Date K短路模板 SPFA+A*
K短路模板,A*+SPFA求K短路.A*中h的求法为在反图中做SPFA,求出到T点的最短路,极为估价函数h(这里不再是估价,而是准确值),然后跑A*,从S点开始(此时为最短路),然后把与S点能达到的点 ...
- BZOJ-1975 魔法猪学院 K短路 (A*+SPFA)
1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec Memory Limit: 64 MB Submit: 1323 Solved: 433 [Submit][Statu ...
- 【POJ】2449 Remmarguts' Date(k短路)
http://poj.org/problem?id=2449 不会.. 百度学习.. 恩. k短路不难理解的. 结合了a_star的思想.每动一次进行一次估价,然后找最小的(此时的最短路)然后累计到k ...
随机推荐
- setfacl命令的基本用法
setfacl命令的基本用法 1.setfacl的用途 setfacl命令可以用来细分linux下的文件权限. chmod命令可以把文件权限分为u,g,o三个组,而setfacl可以对每一个文件或目录 ...
- 仵航说 SpringBoot项目配置Log日志服务-仵老大
今天领导让我配置一个log日志服务,我哪里见过哟,然后就去百度了,结果挨个试下去,找到了一个能用的,分享给大家 大致四个地方 分别是 1.pom文件需要引入依赖 2.创建一个TestLog类 3.在y ...
- 个人微信公众号搭建Python实现 -个人公众号搭建-永久素材管理(14.3.5)
@ 目录 1.说明 2.上传素材 3.获取素材列表 关于作者 1.说明 个人微信公众号开发的功能有限,因为很多权限没有,但支持上传永久素材,具体查看微信公众号文档 这里的请求都要将本地IP地址放到微信 ...
- pandas的学习5-导入导出数据
import pandas as pd ''' pandas可以读取与存取的资料格式有很多种,像csv.excel.json.html与pickle等-, 详细请看官方说明文件 ''' # read ...
- Bootstrap留言板界面练习
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- Google、Facebook等均开始支持的HTTP3到底是个什么鬼?
GitHub 19k Star 的Java工程师成神之路,不来了解一下吗! 最近一段时间以来,关于HTTP/3的新闻有很多,越来越多的国际大公司已经开始使用HTTP/3了. 所以,HTTP/3已经是箭 ...
- 探究虚拟dom与diff算法
一.虚拟DOM (1)什么是虚拟DOM? vdom可以看作是一个使用javascript模拟了DOM结构的树形结构,这个树结构包含整个DOM结构的信息,如下图: 可见左边的DOM结构,不论是标签名 ...
- MySQL5.7.26安装及启动报错解决
一.安装依赖包 [root@db01 ~]# yum install -y lrzsz [文件上传/下载] [root@db01 ~]# yum -y install xfsprogs [安装磁盘格式 ...
- (四)linux的常用环境变量及设置
一.为什么要设置环境变量 1.环境变量能解决什么问题? 你是否经历过输入$python命令后,屏幕上打印出python:command not found的尴尬:每一次都要输入$/home/tools ...
- IDEA和eclips工具对比
描述 eclipse idea 在当前类查找方法 ctrl+o ctrl+F12 查找文件 ctrl+shift+N 大小写转换 ctrl+shift+X ctrl+shift+Y ctrl ...