返回

A* 求 第 k 短路

发布时间:2022-11-04 11:52:53 324
# c++

​​ACM-ICPC 2018 沈阳赛区网络预赛 D. Made In Heaven​​

第 k 短路


想一下 BFS 遍历图,如果没有 vis 数组的限制,也就是说找到终点之后继续 BFS 下去,那么终点第 k 次入队,就是第 k 短路。但是如果直接BFS搜索下去,时间复杂度会非常高,因此我们需要剪枝,怎么剪枝呢?

A* 算法就可很好的剪枝,首先 A* 时基于 BFS,只不过对于队列来说有了一个优先级, BFS 算法只是无脑扩展,但是 A* 用到了一个优先队列,每次出队的结点肯定是优先级最高的结点。每次只需要取出每次到达终点最有希望的路径

最后总结一下流程,
首先建反向图用 SPFA 跑出来终点到各个点的最短路 dis[N]。
用 f[i] 作为优先队列的关键字来进行 A*。
这里 h[i] = dis[i];

题目

存在第 k 短路径,且距离小于 T 就可以,否则不行

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define d(x) cout << (x) << endl
using namespace std;
typedef long long ll;
const int N = 1e3 + 10;
const int M = 1e4 + 10;

int n, m, S, E, K, T;

struct node{
int to, w, ne;
} e[M], re[M]; // 反向边跑 SPFA, 正向边跑 A*

int h[N], rh[N];
int idx;

void init(){
idx = 0;
memset(h, -1, sizeof(h));
memset(rh, -1, sizeof(rh));
}

inline void add(int x, int y, int w){
e[idx].to = y, e[idx].w = w, e[idx].ne = h[x], h[x] = idx; // 正向
re[idx].to = x, re[idx].w = w, re[idx].ne = rh[y], rh[y] = idx++; // 反向
}

int dis[N], vis[N];

// 求出终点到各点的最短长度 dis[i]
// 用这个长度来作为后面 A* 算法的启发式函数 h[i]
void spfa(){
memset(dis, INF, sizeof(dis));
dis[E] = 0; // 从终点开始
queue q;
q.push(E);
vis[E] = 1;
while(!q.empty()){
int cnt = q.front();
q.pop();
vis[cnt] = 0; // 遍历 cnt 的所有边
for (int i = rh[cnt]; ~i; i = re[i].ne){
if(dis[re[i].to] > dis[cnt] + re[i].w){
dis[re[i].to] = dis[cnt] + re[i].w;
if(!vis[re[i].to]){
vis[re[i].to] = 1;
q.push(re[i].to);
}
}
}
}
}

struct A{ // 优先队列默认弹出大的,所以这样重载
int id, g, f; // id 是点的号
// 核心式子 : f = g + h,这里 h(i) = dis[i];
bool operator < (const A& b) const {
if(f == b.f)
return g > b.g;
return f > b.f;
}
};

int Astar(){
int res = 0;
if(S == E) //判断相同点算不算最短路
K++;
if(dis[S] == INF)
return -1; // 起点终点没有通路
priority_queue q; //优先队列 默认教大的值先出队列
q.push(A{S, 0, 0 + dis[S]});
while(!q.empty()){
A cnt = q.top();
q.pop();
if(cnt.id == E){
res++;
if(res == K) // 第 k 次到达就是结果
return cnt.g;
}
for(int i = h[cnt.id]; ~i; i = e[i].ne){
int a = e[i].to; // 估计代价
int b = cnt.g + e[i].w; // 实际代价
int c = b + dis[a];
q.push(A{a, b, c});
}
}
return -1; // 没有第 k 短路
}

int main()
{
while(~scanf("%d%d", &n, &m)){
init();
scanf("%d%d%d%d", &S, &E, &K, &T);
for (int i = 1, x, y, w; i <= m; i++){
scanf("%d%d%d", &x, &y, &w);
add(x, y, w);
}
spfa();
int ans = Astar();
// cout << ans << endl;
if(ans != -1 && ans <= T)
printf("yareyaredawa\n");
else
printf("Whitesnake!\n");
}
return 0;
}

 

特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线