A*算法求最短路
A*算法思想:
算法通过一个估价函数f(h)来估计图中的当前点p到终点的距离,并由此决定它的搜索方向;当这条路径失败时,它会尝试其他路径;
对于A*,估价函数=当前值+当前位置到终点的距离,即f(p)=g(p)+h(p),每次扩展估价函数值最小的一个;
对于K短路算法来说,g(p)为当前从s到p所走的路径的长度;h(p)为点p到t的最短路的长度;
f(p)的意义为从s按照当前路径走到p后再走到终点t一共至少要走多远;
为了加速计算,h(p)需要在A*搜索之前进行预处理,从终点t做一次单源点最短路径就能得到每个点的h(p)了;
步骤:
(1)以原终点t为源点,跑一次单源最短路
(2)新建一个优先级队列,将源点s加入到队列中
(3)从优先级队列中弹出f(p)距离最小的点p,如果点p就是t,则计算t出队的次数;
如果当前为t的第k次出队,则当前路径的长度就是s到t的第k短路的长度,算法结束;
否则遍历与p相连的所有的边,将扩展出的到p的邻接点信息加入到优先级队列;
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<queue>
using namespace std;
int n,m,s,t,k,cnt,tot;
const int maxn=1005;
const int maxm=1e5+5;
typedef long long ll;
const ll inf=1e18;
int head[maxn],rhead[maxn],vis[maxn];
struct edge
{
int to,nxt;
ll v;
}e[maxm<<1],re[maxm<<1];
ll dis[maxn];
void add(int x,int y,int z)
{
e[++cnt].to=y;
e[cnt].nxt=head[x];
e[cnt].v=z;
head[x]=cnt;
}
void ADD(int x,int y,int z)
{
re[++tot].to=y;
re[tot].nxt=rhead[x];
re[tot].v=z;
rhead[x]=tot;
}
void dijkstra(int x)
{
priority_queue <pair<ll,int> > q;
for(int i=1;i<=n;i++) dis[i]=inf;
dis[x]=0;
q.push(make_pair(-dis[x],x));
while(!q.empty())
{
pair<ll,int> u=q.top();
q.pop();
if(vis[u.second]) continue;
vis[u.second]=1;
ll num=-u.first;
for(int i=rhead[u.second];i;i=re[i].nxt)
{
int to=re[i].to;
if(!vis[to] && dis[to]>num+re[i].v)
{
dis[to]=num+re[i].v;
q.push(make_pair(-dis[to],to));
}
}
}
}
void init()
{
cnt=tot=0;
memset(head,0,sizeof(head));
memset(rhead,0,sizeof(rhead));
memset(vis,0,sizeof(vis));
}
struct Node
{
int pos; ll f;
bool operator <(Node const &oth) const
{
return oth.f+dis[oth.pos]<f+dis[pos];
}
Node (int a,ll c):pos(a),f(c) {}
};
ll astar(int x)
{
priority_queue <Node> que;
que.push(Node(x,0));
while(!que.empty())
{
Node u=que.top();
que.pop();
if(u.pos==t)
{
k--;
if(!k) return u.f;
}
for(int i=head[u.pos];i;i=e[i].nxt)
{
int to=e[i].to;
que.push(Node(to,u.f+e[i].v));
}
}
return -1;
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
while(scanf("%d%d",&n,&m)!=EOF)
{
int x,y;ll z;
init();
for(int i=1;i<=m;i++)
{
scanf("%d%d%lld",&x,&y,&z);
add(x,y,z); ADD(y,x,z);
}
scanf("%d%d%d",&s,&t,&k);
dijkstra(t);
if(dis[s]==inf)
{
printf("-1\n");
continue;
}
if(s==t) k++;
ll ans=astar(s);
printf("%lld\n",ans);
}
return 0;
}