初次理解A*stra

A* star 算法

第K短路
问题链接

A*  star 特征:点数特别多。 
此算法前置技能: Dijkstra 最短路
该算法与Dijkstra算法不同:Dijkstra按照dist[s]排序,而该算法按照dist[s] + f(s) 排序。
f(s) 为估价函数,只要 f(s)  <= g(s) (g(s)为真实距离 ,
即从s到目标点的真实距离),  
就可以保证 当某个状态s,第一次优先队列中出来是 他的距离	就一定是最短距离了。
如果f(s) == 0,则退化为Dijkstra算法。
t为s的下一个节点
dist[s] + f(s) <= dist[t] + f(t) <= dis[t] + g(t) + edge(t->s);



1.在宽搜(最短路)问题中, 如果所有边权都是非负的,
 那么就可以使用启发函数来优化BFS过程。
2.核心思想:
 (1): 建立反向图, 在反向图中求出目标点(T)到所有点的最短距离,
 作为每个点的估价函数。
 (2):从起点(S)开始扩展,
 每次取出当前估价值最小的点,将其能扩展的点全部不扩展。(扩展就是宽搜 把能到的点全部加入优先队列)。
 估计值 = 距离起点的真实距离 + 估价函数。
 (3):当第K次遇到T; 就求出了从S到T的第K短路了;

下面是函数区:

#include <stdio.h>
#include <queue>
#include <string.h>
#include <string>
#include <algorithm>
using namespace std;
const int N = 1010, M =  200010;
typedef pair<int, int> PII;
typedef pair<int, PII> PIII;
int h[M], rh[M] ,e[M], en[M], w[M], cnt;
int S, T, K;
int dis[M], f[M] ,vis[M];
//建立邻接表:
void add (int *h, int a, int b, int c)
{
    e[cnt] = b;
    w[cnt] = c;
    en[cnt] = h[a];
    h[a] = cnt ++;
}
//利用该函数求目标点到每个点的最短路:
void Dijkstra()
{
    priority_queue<PII, vector<PII>, greater<PII> > head;
    memset(vis, 0, sizeof vis);
    memset(dis, 0x3f, sizeof dis);
    dis[T] = 0;
    head.push({0, T});
    while (head.size())
    {
        PII t =head.top();
        head.pop();
        int s = t.second;
        if (vis[s]) continue;
        vis[s] = 1;
        for (int i = rh[s]; ~i; i = en[i])
        {
            int j = e[i];
            if (dis[j] > dis[s] + w[i])
            {
                dis[j] = dis[s] + w[i];
                head.push({dis[j], j});
            }
        }
    }
    
    memcpy(f, dis, sizeof f);  //f 为估价函数 与dis值一样 复制一下w是为了更加容易理解
}
int a_star()
{
    priority_queue <PIII, vector<PIII>, greater<PIII> > p;
    
    p.push({f[S], {0, S}}); //利用估价值排序 即真实距离+估价函数
    memset(vis, 0, sizeof vis);
    
    while (p.size())
    {
        PIII t = p.top();
        p.pop();
        int ver = t.second.second, distance = t.second.first;
        if (vis[ver] >= K) continue;
        vis[ver] ++ ;
        if (ver == T && vis[ver] == K) return distance;
        for (int i = h[ver]; ~i; i = en[i])
        {
            int j = e[i];
            if (vis[j] < K)
                p.push({distance + w[i] + f[j], {distance + w[i], j}});
        }
    }
    return -1;
}
int main ()
{
    int n, m;
    scanf ("%d%d", &n, &m);
    memset(h, -1, sizeof h);
    memset(rh, -1, sizeof rh);
    for (int i = 0; i < m; i ++ )
    {
        int a, b, c;
        scanf ("%d%d%d", &a, &b, &c);
        add(rh, b, a, c);      //建立反向图
        add(h, a, b, c);       //正向图
    }
    scanf ("%d%d%d", &S, &T, &K);
    if (S == T) K ++ ;
    Dijkstra();       //求从T到所有点的最短距离作为每个点的估价函数
    printf ("%d\n", a_star());
    return 0;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值