1. 定义
A* 算法(A-Star)是一种静态路网中求解最短路径最有效的直接搜索方法,也是解决许多搜索问题的有效算法。算法中的距离估算值与实际值越接近,最终搜索速度越快。
2. 原理
A* [1] (A-Star)算法是一种静态路网中求解最短路径最有效的直接搜索方法,也是许多其他问题的常用启发式算法。注意——是最有效的直接搜索算法,之后涌现了很多预处理算法(如ALT,CH,HL等等),在线查询效率是A*算法的数千甚至上万倍。
公式表示为: f(n)=g(n)+h(n)
,
其中,
-
f(n) 是从初始状态经由状态n到目标状态的代价估计,
-
g(n) 是在状态空间中从初始状态到状态n的实际代价,
-
h(n) 是从状态n到目标状态的最佳路径的估计代价。(对于路径搜索问题,状态就是图中的节点,代价就是距离)
h(n)的选取
保证找到最短路径(最优解的)条件,关键在于估价函数f(n)的选取(或者说h(n)的选取)。
我们以d(n)表达状态n到目标状态的距离,那么h(n)的选取大致有如下三种情况: -
如果h(n)< d(n)到目标状态的实际距离,这种情况下,搜索的点数多,搜索范围大,效率低。但能得到最优解。
-
如果h(n)=d(n),即距离估计h(n)等于最短距离,那么搜索将严格沿着最短路径进行, 此时的搜索效率是最高的。
-
如果 h(n)>d(n),搜索的点数少,搜索范围小,效率高,但不能保证得到最优解
题目
输入格式 |
---|
第一行包含两个整数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≤105 ,
1≤K≤1000,
1≤L≤100
输入样例 |
---|
2 2
1 2 5
2 1 4
1 2 2
输出样例:
14
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> PII;
typedef pair<int, PII> PIII;
int n, m, S, T, K;
int dist[N], st[N];
int idx, h[N], rh[N], e[N], ne[N], w[N];
void add(int *h, int a, int b, int c)
{
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
//反方向求最短路
void dijkstra()
{
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0, T});
memset(dist, 0x3f, sizeof dist);
dist[T] = 0;
while (heap.size())
{
auto t = heap.top();
heap.pop();
int distance = t.first, ver = t.second;
if (st[ver])
continue;
st[ver] = true;
for (int i = rh[ver]; ~i; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[ver] + w[i])
{
dist[j] = dist[ver] + w[i];
heap.push({dist[j], j});
}
}
}
}
//将dist[i]当作估价函数
int A_star()
{
priority_queue<PIII, vector<PIII>, greater<PIII>> heap; //小根堆维护数据,根据distance +w[i]+dist[j](此条路S到T的距离)排序,每次取最小的遍历,最后st[T]==K的路径即为最小最短路
heap.push({dist[S], {0, S}});
memset(st, 0, sizeof st);
while (heap.size())
{
auto t = heap.top();
heap.pop();
int ver = t.second.second, distance = t.second.first;
st[ver]++;
if (ver == T && st[ver] == K)
return distance;
for (int i = h[ver]; ~i; i = ne[i])
{
int j = e[i];
heap.push({distance + w[i] + dist[j], {distance + w[i], j}});
}
}
return -1;
}
int main()
{
cin >> n >> m;
memset(rh, -1, sizeof rh);
memset(h, -1, sizeof h);
for (int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
add(h, a, b, c);
add(rh, b, a, c);
}
cin >> S >> T >> K;
if (S == T)
K++;
dijkstra();
cout << A_star() << endl;
return 0;
}