1.1.4k短路

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;
}

猜你喜欢

转载自blog.csdn.net/andyc_03/article/details/113087558
今日推荐