在dijkstra中,终点第一次出队时即为最小值,而中间点第一次出队不一定为最小值
同样,终点第k次出队即为第k短路,而中间点不一定
解题思路:
首先在反向图上从终点开始dijkstra,求出每个点到终点的最短距离,用于计算估价函数
然后在正向图上做A*的BFS,估价函数为起点到该点的真实距离+该点到终点的最短距离
当终点第k次出队时即找到第k短路
#include<iostream>
#include<cstring>
#include<map>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m;
int S,T,K;
const int N=1005,M=1e5+5;
int h[N],e[M],w[M],ne[M],idx;
int rh[N];
bool vis[N];
int dis[N];
typedef pair<int,int> PII;
typedef pair<int,pair<int,int> > PIII;
void add(int h[],int a,int b,int c)
{
e[idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
//反向图上从终点开始dijkstra
//求出每个点到终点的最短距离,用于计算估价函数
void dijkstra()
{
priority_queue<PII,vector<PII>,greater<PII> > q;
memset(dis,0x3f,sizeof dis);
dis[T]=0;
q.push({0,T});
while(q.size())
{
PII t=q.top();q.pop();
int ver=t.second,distance=t.first;
if(vis[ver]) continue;
vis[ver]=true;
for(int i=rh[ver];i!=-1;i=ne[i])
{
int j=e[i];
if(dis[j]>distance+w[i])
{
dis[j]=distance+w[i];
q.push({dis[j],j});
}
}
}
}
int astar()
{
if(dis[S]==0x3f3f3f3f) return -1;
priority_queue<PIII,vector<PIII>,greater<PIII> > q;
q.push({dis[S],{0,S}});
int cnt=0;
while(q.size())
{
PIII t=q.top();q.pop();
int ver=t.second.second;
int distance=t.second.first;
if(ver==T) cnt++;
if(cnt==K) return distance;
//估价函数为 起点到该点的真实距离+该点到终点的最短距离
for(int i=h[ver];i!=-1;i=ne[i])
{
int j=e[i];
q.push({distance+w[i]+dis[j],{distance+w[i],j}});
}
}
return -1;
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
memset(rh,-1,sizeof rh);
for(int i=0;i<m;i++)
{
int a,b,c;cin>>a>>b>>c;
add(h,a,b,c);
add(rh,b,a,c);
}
cin>>S>>T>>K;
if(S==T) K++;
dijkstra();
cout<<astar();
}