蒟蒻林荫小复习——K短路的A*解法

Posted xlinyin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蒟蒻林荫小复习——K短路的A*解法相关的知识,希望对你有一定的参考价值。

看标题都知道讲的是什么,但为什么特指是A*关于K短路的解法呢?

因为林荫不会其他的。

能看到这篇博客的估计也都知道K短路和A*分别是什么了吧,下面只介绍一下估价函数

由于林荫并没有经过学术训练,所以一下关于A*的理解均为感性,仅可作为OIer速成知识点时的一点资料,

切莫作为算法学术依据。

先思考一下,对于任意一条K短路,是不是均可写成由一部分最短路和一部分其他路径组成,而且这两部分路径还有且仅有一个公共点。

说明:1.任何一条路径都可以视为由其他到终点的路径和终点到终点的最短路组成

   2.哪怕前面的路径上有环,最短路也一定和其他的路径在环的出点上相连。因为一旦最短路和路径上其他点相交,就代表该最短路上有环,那么这条路径就不是最短路。

好的,下面引入概念:估价函数!

实际上没啥特别的,就一个公式 F(x)=G(x)+H(x),F(x)是该路线的期望花费,G(x)是从起点到当前点的花费,H(x)是当前点到终点的最优花费。

那么,我们在求解的时候是不是有个大致思路了?

K值越小的路径的X点离起点越近(大概就这个意思,也可以认为越接近最短路的路线所使用的最短路越多)

那么我们是否可以考虑先将H处理出来(建反图,求单源最短路),然后维护一个优先队列,队列里面保存一个Pair(F(x)和x点),那么我们每次根据F(x)的值决定下一个执行的点,如果x已经是终点了,就该统计答案统计答案,该返回返回,否则针对x计算出每一个相连接的点to,求出F(to)后压入队列,直到完成K个路径或者发现当前最短的一条路径已经不满足需求。

下面放个代码吧,例题COGS3227

严格来说这个并不算K短路,而是给定特殊限制,求满足条件的路径

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
vector<pair<int,int> > b[1001],fb[1001];
int vis[1001],dis[1001];
int n,m,a1,a2,a3,S,F,ans,MX,T;
void DIJ()
{
    memset(dis,0x3f3f3f3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    priority_queue<pair<int,int> > q; 
    dis[F]=0;
    q.push(make_pair(0,F));
    while(q.size())
    {
        int u=q.top().second;
        q.pop();
        if(vis[u])
            continue;
        vis[u]=1;
        for(int i=0;i<fb[u].size();i++)
        {
            int to=fb[u][i].first;
            if(dis[to]>dis[u]+fb[u][i].second)
            {
                dis[to]=dis[u]+fb[u][i].second;
                q.push(make_pair(-dis[to],to));
            }
        }
    }
}
void ASTAR()
{
    priority_queue<pair<int,int> > q;
    q.push(make_pair(-dis[S],S));
    while(q.size())
    {
        int u=q.top().second;
        int v=q.top().first;
        q.pop();
        int dist=-v-dis[u];//实际上从起点到u的距离
        if(dist>MX)
            continue;
        if(u==F)
        {
            if(dist<=MX)
            {
                ans++;
            }
            else
                return;
        } 
        for(int i=0;i<b[u].size();i++)
        {
            int to=b[u][i].first;
            q.push(make_pair(-(dist+b[u][i].second+dis[to]),to));
        }
    }
}
int LINYIN()
{
    ans=0;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        b[i].clear();
        fb[i].clear();
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a1,&a2,&a3);
        fb[a2].push_back(make_pair(a1,a3));
        b[a1].push_back(make_pair(a2,a3));
    }
    scanf("%d%d",&S,&F);
    DIJ();
    MX=dis[S]+1;
    ASTAR();
    printf("%d
",ans);
    return 0;
}
int LWH()
{
    freopen("sightseeing.in","r",stdin);
    freopen("sightseeing.out","w",stdout);
    scanf("%d",&T);
    while(T--)
    {
        LINYIN();
    }
    return 0;
}
int MYLOVE=LWH();
int main()
{
    ;
}

完结撒花!!!

 

以上是关于蒟蒻林荫小复习——K短路的A*解法的主要内容,如果未能解决你的问题,请参考以下文章

蒟蒻林荫的小复习——主席树

蒟蒻林荫小复习——带权并查集

蒟蒻林荫小复习——KMP算法

noip级别模板小复习

C语言结构题小复习

小复习