给定一张N个点(编号1,2…N),M条边的有向图,求从起点S到终点T的第K短路的长度,路径允许重复经过点或边。

注意: 每条最短路中至少要包含一条边。

输入格式
第一行包含两个整数N和M。

接下来M行,每行包含三个整数A,B和L,表示点A与点B之间存在有向边,且边长为L。

最后一行包含三个整数S,T和K,分别表示起点S,终点T和第K短路。

输出格式
输出占一行,包含一个整数,表示第K短路的长度,如果第K短路不存在,则输出“-1”。

数据范围
1≤S,T≤N≤1000,
0≤M≤105,
1≤K≤1000,
1≤L≤100
输入样例:
2 2
1 2 5
2 1 4
1 2 2
输出样例:
14

A∗ 算法在人工智能中是一种典型的启发式搜索算法
启发中的估价是用估价函数表示的:
h(n) = f(n) + g(n)
其中 f(n) 是节点n的估价函数
g(n) 表示实际状态空间中从初始节点到n节点的实际代价
h(n) 是从n到目标节点最佳路径的估计代价。
另外定义 h’(n) 为n到目标节点最佳路径的实际值。
如果 h’(n) ≥ h(n) 则如果存在从初始状态走到目标状态的最小代价的解
那么用该估价函数搜索的算法就叫 A∗ 算法。

这就是一个简单的 A_star 搜索,然后我们求一下估价函数,也就是每个点到终点的距离,然后按照估价函数和当前的移动距离,排序即可。A_star 和 bfs 十分像,只不过我们加一个排序的权值。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int n,m,s,t,k,f[N],a[N],b[N],c[N];
int head[N],nex[N],to[N],w[N],tot;
struct node{
	int u,d,fx;
};
bool operator < (node a,node b){
	return a.fx>b.fx;
}
inline void add(int a,int b,int c){
	to[++tot]=b; w[tot]=c; nex[tot]=head[a]; head[a]=tot;
}
void dijkstra(){
	priority_queue<pair<int,int> > pq;	pq.push({0,t});
	memset(f,0x3f,sizeof f);	f[t]=0;	int vis[N]={0};
	while(pq.size()){
		auto u=pq.top().second;	pq.pop();
		if(vis[u])	continue;	vis[u]=1;
		for(int i=head[u];i;i=nex[i]){
			if(f[to[i]]>f[u]+w[i]){
				f[to[i]]=f[u]+w[i];	pq.push({-f[to[i]],to[i]});
			}
		}
	} 
}
int a_star(){
	priority_queue<node> pq;	pq.push({s,0,f[s]});
	int vis[N]={0};
	while(pq.size()){
		int u=pq.top().u;	int dis=pq.top().d;	pq.pop();
		if(vis[u]>=k)	continue;	vis[u]++;
		if(vis[u]==k&&u==t)	return dis;
		for(int i=head[u];i;i=nex[i]){
			if(vis[to[i]]<k)
				pq.push({to[i],dis+w[i],dis+w[i]+f[to[i]]});
		}
	}
	return -1;
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>a[i]>>b[i]>>c[i];	add(b[i],a[i],c[i]);	
	}
	cin>>s>>t>>k;	if(s==t)	k++;
	dijkstra();	tot=0;	memset(head,0,sizeof head);
	for(int i=1;i<=m;i++)	add(a[i],b[i],c[i]);
	cout<<a_star()<<endl;	
	return 0;
}