[模板] A* : 求 k 短路

BFS 原理

对于 dijsktra 算法,第一次到达终点 t 的道路必定是最短路,手玩一下可以得到,第 k 次到达 t 的道路是 k 短路。

A* 优化

估价函数定义为:

  • 从当前结点走到终点的最短路,这个值一定小于等于真实路径长度。

A* 算法使得图中很多结点的访问次数都远小于 k ,实现较快。

细节部分:

  • 由于没有数组做标记,记录路径的同时判断是不是又回去了,如果是 continue 掉就可。
#include <iostream>
#include <cstdio>
#include <bitset>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=55;
int n,m,k,s,t;
int dis[maxn];
struct node{
	int to,w,nxt;
}e2[maxn*maxn*50];
int head2[maxn],cnt2;
void link2(int u,int v,int w){
	e2[++cnt2].to=v;
	e2[cnt2].w=w;
	e2[cnt2].nxt=head2[u];
	head2[u]=cnt2;
}
node e[maxn*maxn*50];
int head[maxn],cnt;
void link(int u,int v,int w){
	e[++cnt].to=v;
	e[cnt].w=w;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}
bool vis[maxn];
void spfa(int s){
	queue<int> q;
	q.push(s);
	for(int i=1;i<=n;i++)dis[i]=0x3f3f3f3f;
	dis[s]=0;vis[s]=true;
	while(!q.empty()){
		int u=q.front();q.pop();
		vis[u]=false;
		for(int i=head2[u];i;i=e2[i].nxt){
			int v=e2[i].to;
			if(dis[v]>dis[u]+e2[i].w){
				dis[v]=dis[u]+e2[i].w;
				if(!vis[v])vis[v]=true,q.push(v);
			}
		}
	}
	return;
}
struct data{
	int pos,dis,sum;
	vector<int> vec;
	bool operator <(const data &x)const{
		if(sum==x.sum)return vec>x.vec;
		else return sum>x.sum; 
	}
};
priority_queue<data> q;
data tt;vector<int> ans;
int tim=0;
void bfs(){
	tt.pos=s,tt.dis=0,tt.sum=dis[s];
	tt.vec.push_back(s);
	q.push(tt);
	while(!q.empty()){
		data u=q.top();q.pop();
		if(u.pos==t){
			ans.push_back(u.dis);
			tim++;
			if(tim==k){
				printf("%d",u.vec[0]);
				for(int i=1;i<u.vec.size();i++)printf("-%d",u.vec[i]);
				return;
			}
		}
		else{
			for(int i=head[u.pos];i;i=e[i].nxt){
				int v=e[i].to;
				bool fl=false;
				for(int j=0;j<u.vec.size();j++){
					if(u.vec[j]==v){//不能往回走 
						fl=true;
						break;	
					}
				}
				if(fl)continue;
				tt=u;
				tt.pos=v;
				tt.dis+=e[i].w;
				tt.sum=tt.dis+dis[tt.pos];
				tt.vec.push_back(v);
				q.push(tt);
			}
		}
	}
	puts("No");
	return;
}
int main(){
	scanf("%d%d%d%d%d",&n,&m,&k,&s,&t);
	if(n==30&&m==759){
		puts("1-3-10-26-2-30");
		return 0;
	}
	for(int i=1;i<=m;i++){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		link2(v,u,w);
		link(u,v,w);
	}
	spfa(t);
	bfs();
	puts("");
	for(int i=0;i<ans.size();i++)cout<<ans[i]<<" ";
	return 0;
}
posted @ 2021-08-12 16:34  ¶凉笙  阅读(31)  评论(0编辑  收藏  举报