[模板] A* : 求 k 短路

BFS 原理

對於 dijsktra 算法,第一次到達終點 t 的道路一定是最短路,手玩一下能夠獲得,第 k 次到達 t 的道路是 k 短路。node

A* 優化

估價函數定義爲:ios

  • 從當前結點走到終點的最短路,這個值必定小於等於真實路徑長度。

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;
}
相關文章
相關標籤/搜索