K短路及其模板(A*+Dijkstra)

阅读之前,先声明,您不需要对于A*算法多么深入的理解,事实上这对您对于K短路的理解帮助并不很大。当然,若果您对于A*已经有了自己独到见解,也是很好的。

A*

用非专业的语言来说,A*就是一个将最好的选择,送上你面前的算法。打个比方,您在一个叉路口,面前有几条路。A*做的,便是告诉您哪一条路是您最好的选择。

有一个这样的估价函数

        F = G + H

您可以简单的理解为F为您选择道路的标准,G是一个影响因素,H是另外一个影响因素。如果您的 F 比较贴近实际情况,也就是说估价函数贴近实际情况,总能(或在大部分情况下)给您最好的选择,那么您的算法是非常有效率的。
反之,就像选取路径的标准是天气如何一样,您的算法效率将不会那么的高。

以上的描述只能帮助您理解,而不是标准甚至正确的说法。

Dijkstra

在队列中,如果我们每次找到距离最短的一个点去更新其他点,当这个点出队第K次的时候,当前的距离就是到该点的第k短路。我们将这个点类推为重点,则得到,当终点出现第k次的时候,我们求得了从起点到终点的第K短路。

这个过程可以用Dijkstra实现。我们同时设置了这么一个估价函数

F = G  +  H 
G :该点到起点的距离
H :该点到终点的距离

每一次进行更新距离时,同时更新估价函数F,最后使用堆或优先队列维护。事实上,除了上述这种估价函数的描述以外,还有很多其他的写法,他们的本质上都是一样的。

代码如下

//K-th_Road.cpp
//
//Glasses
#include <map>
#include <queue>
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL int
#define MAXN 100005
#define MOD 1000000007
#define INF 0x7f7f7f7f
#define FOR(i,a,b) for(LL i = (a), i##end = (b); i <= i##end; ++i)
#define ROF(i,a,b) for(LL i = (a), i##begin = (b); i >= i##begin; --i)
#define put0(str) memset( (str) , 0, sizeof( (str) ));
#define putinf(str) memset( (str) , INF ,sizeof((str)));
#define output(a) printf("%d\n",(a));
#define input(a) scanf("%d",&(a));
LL read()
{  
    LL x=0,tag=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')tag=-1;ch=getchar();}
    while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();  
    return x*tag;
}

struct k_th
{
    struct Node
    {
        LL x,f,h;
        Node(){}
        Node(LL a,LL b,LL c) : x(a),f(b),h(c){}
        bool operator < (const Node& rhs) const
        {
            if(h==rhs.h)return f>rhs.f;
            return h>rhs.h;
        }
    };

    struct Edge
    {
        LL to,nxt,w;
        Edge(){}
        Edge(LL a,LL b,LL c):to(a),nxt(b),w(c){}
    };

    Edge edges[MAXN],redges[MAXN];
    LL n,cnte,rcnte,k;
    LL dis[1010],vis[1010],rhead[1010],head[1010];

    void init(LL inn,LL ink)
    {
        this->n=inn;this->k=ink+1;cnte=rcnte=0;
        put0(head);
    }

    void add_edge(LL a,LL b,LL c)
    {
        edges[++cnte]=Edge(b,head[a],c);head[a]=cnte;
        redges[++rcnte]=Edge(a,rhead[b],c);rhead[b]=rcnte;
    }

    queue<LL> q;

    void spfa(LL st)
    {
        while(!q.empty())q.pop();
        put0(vis);putinf(dis);
        q.push(st);
        dis[st]=0;vis[st]=1;
        while(!q.empty())
        {
            LL x=q.front();q.pop();vis[x]=0;    
            for(LL i=rhead[x];i;i=redges[i].nxt)
            {
                if(dis[redges[i].to]>dis[x]+redges[i].w)
                {
                    dis[redges[i].to]=dis[x]+redges[i].w;
                    if(!vis[redges[i].to])
                    {
                        vis[redges[i].to]=1;
                        q.push(redges[i].to);
                    }
                }
            }
        }
    }

    priority_queue<Node> qq;
    LL Astar(LL st,LL ed)
    {
        spfa(ed);
        put0(vis);
        if(dis[st]==INF)return -1;
        if(st==ed)k++;
        qq.push(Node(st,0,dis[st]));
        while(!qq.empty())
        {
            Node x=qq.top();qq.pop();
            ++vis[x.x];
            if(vis[x.x]>k)continue;
            if(vis[ed]==k)return x.f;
            for( LL i=head[x.x];i;i=edges[i].nxt )
            {
                LL t1=x.f+edges[i].w;
                LL t2=t1+dis[edges[i].to];
                qq.push( Node(edges[i].to,t1,t2) );
            }
        }
        return -1;
    }
}e;

错误是我的,请让我吃掉:(

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/GlassesQ/article/details/52842123
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞