A*算法入门(AcWing 178. 第K短路、AcWing 179. 八数码)

1. 定义

A* 算法(A-Star)是一种静态路网中求解最短路径最有效的直接搜索方法,也是解决许多搜索问题的有效算法。算法中的距离估算值与实际值越接近,最终搜索速度越快。

2. 原理

A* [1] (A-Star)算法是一种静态路网中求解最短路径最有效的直接搜索方法,也是许多其他问题的常用启发式算法。注意——是最有效的直接搜索算法,之后涌现了很多预处理算法(如ALT,CH,HL等等),在线查询效率是A*算法的数千甚至上万倍。
公式表示为: f(n)=g(n)+h(n),
其中,

  1. f(n) 是从初始状态经由状态n到目标状态的代价估计,

  2. g(n) 是在状态空间中从初始状态到状态n的实际代价,

  3. h(n) 是从状态n到目标状态的最佳路径的估计代价。(对于路径搜索问题,状态就是图中的节点,代价就是距离)
    h(n)的选取
    保证找到最短路径(最优解的)条件,关键在于估价函数f(n)的选取(或者说h(n)的选取)。
    我们以d(n)表达状态n到目标状态的距离,那么h(n)的选取大致有如下三种情况:

  4. 如果h(n)< d(n)到目标状态的实际距离,这种情况下,搜索的点数多,搜索范围大,效率低。但能得到最优解。

  5. 如果h(n)=d(n),即距离估计h(n)等于最短距离,那么搜索将严格沿着最短路径进行, 此时的搜索效率是最高的。

  6. 如果 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;
}

发布了84 篇原创文章 · 获赞 12 · 访问量 2922

猜你喜欢

转载自blog.csdn.net/qq_43294914/article/details/103267108