阅读之前,先声明,您不需要对于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;
错误是我的,请让我吃掉:(