[A_Star]刷题记录之启发式搜索🔥

254 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路 持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

A_Star算法的本质是基于贪心的dijkstra,它在我们熟悉的dijkstra算法上加上了对于f函数的贪心;

那么在学习A_Star算法之前我们需要先搞懂三个函数变量

g() 从起点移动到指定点的移动代价 <走到目前点已经花费的体力值>
h() 从指定点移动到终点的估算成本 <从目前点到终点预估的还需要花费的体力值>
f() 总估值  <g()+h()> 

我们的A_Star算法在运行过程中就是在二叉堆中不断地以f()为贪心标准,每次都取出当前的二叉堆中f()最小的点,下文中为了方便我们将这个点称为 <关键点>;

因为他是最有希望能耗费最低体力值到达终点的点

然后我们遍历与当前点相邻的点,倘若相邻点是不能走的点那便不进行任何操作,要是尚未处在二叉堆中,那就把它加入二叉堆

要是某个相邻点处在的f()=g()+h(),能够通过<关键点>来优化g(),那就更新这个相邻点的f()=g()’+h()

这里附上一道A*例题

178. 第K短路

  •    题目 给定一张 N 个点(编号 1,2…N),M 条边的有向图,求从起点S 到终点 T 的第 K 短路的长度,路径允许重复经过点或边。

注意:  每条最短路中至少要包含一条边。

输入格式

第一行包含两个整数 N 和 M。

接下来 M 行,每行包含三个整数 A,B 和 L,表示点 A 与点 B 之间存在有向边,且边长为 L。

最后一行包含三个整数 S,T 和 K,分别表示起点S,终点 T 和第 K 短路。

输出格式

输出占一行,包含一个整数,表示第 K 短路的长度,如果第 K 短路不存在,则输出 −1。

数据范围

1≤S,T≤N≤1000,
0≤M≤104,
1≤K≤1000,
1≤L≤100

输入样例:

2 2
1 2 5
2 1 4
1 2 2

输出样例:

14

cpp代码

#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
typedef pair<int, PII> PIII;
const int N = 1010, M = 200010;
int n, m, op, ed, k;
int bian[2][N],cnt,a,b,c,dis[N], shu[N];
bool st[N];
struct edge { int to, last, d; }e[M];
void add(int bian[], int u, int v, int d){
	e[++cnt].to = v;
	e[cnt].d = d;
	e[cnt].last = bian[u];
	bian[u] = cnt;
}
void dijkstra(int bian[]){
	priority_queue<PII, vector<PII>, greater<PII>> heap;
	heap.push({ 0,ed });
	memset(dis, 0x3f, sizeof dis);
	dis[ed] = 0;
	while (heap.size()){
		auto t = heap.top();heap.pop();
		int ver = t.y;
		if (st[ver]) continue;st[ver] = true;
		for (int i = bian[ver]; i; i = e[i].last){
			int j = e[i].to;
			if (dis[j] > dis[ver] + e[i].d)
				dis[j] = dis[ver] + e[i].d,
				heap.push({ dis[j],j });
		}
	}
}
int astar(int bian[]){
	priority_queue<PIII, vector<PIII>, greater<PIII>> heap;
	heap.push({ dis[op], {0, op} });
	while (heap.size()){
		auto t = heap.top();
		heap.pop();
		int ver = t.y.y, distance = t.y.x;
		shu[ver]++;
		if (shu[ed] == k) return distance;
		for (int i = bian[ver]; i; i = e[i].last){
			int j = e[i].to;
			if (shu[j] < k)
				heap.push({ distance + e[i].d + dis[j],{distance +e[i].d,j} });
		}
	}return -1;
}
int main(){
	cin >> m >> n;
	for (int i = 1; i <= n; i++){
		cin >> a >> b >> c;
		add(bian[0], a, b, c);
		add(bian[1], b, a, c);
	}
	cin >> op >> ed >> k;
	if (op == ed) k++;
	dijkstra(bian[1]);
	cout << astar(bian[0]);
	return 0;
}