解题思路
本题的题目题目要求就是求给定图的K短路。
在此之前,我只可以求解最短路问题,而学了A*之后就可以求解这一类问题。
A*的概念
A*是一种广泛用于寻路的算法。之所以其能运用广泛是因为A*效率极高。主要思想就是通过当前最小成本(最小距离或时间)来解决方案。
A*的实现过程
A*有点类似于spfa,但是A*选择最短的路径是通过函数
f(n)=g(n)+h(n)
,其中g(n)是起点到n的代价,h(n)则是估价函数(估价函数随题目的不同而不同,在网格图中一般使用曼哈顿距离拿来估价,地图中则是直线距离)。并且A*通过优先队列来实行重复的选择最小成本。
K短路的实现
K短路的估价函数就是n到终点的最短路(这个可以提前用spfa预处理处理),显然第K次达到终点就是K短路。
时间复杂度
最坏的时空复杂度都为b^d,但是显然比这个值小,所以效率玄学。
下面这张图有助于理解,估价函数是曼哈顿距离。
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=1005,maxm=100005;
int nxt[maxm][2],son[maxm][2],tot[2],lnk[maxn][2],w[maxm][2];
int n,m,s,t,k,num,que[maxn],hed,til,dst[maxn];
bool vis[maxn];
struct jz{
int x,w;
bool operator<(const jz &b)const{
return w+dst[x]>b.w+dst[b.x];
}
};
priority_queue<jz> heap;
inline int _read(){
int num=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();
return num;
}
void add(int d,int x,int y,int z){
nxt[++tot[d]][d]=lnk[x][d];lnk[x][d]=tot[d];son[tot[d]][d]=y;w[tot[d]][d]=z;
}
void spfa(){
memset(dst,63,sizeof(dst));
til=1;que[1]=t;vis[t]=1;dst[t]=0;
while (hed!=til){
hed=(hed+1)%maxn;
int x=que[hed];vis[x]=0;
for (int j=lnk[x][1];j;j=nxt[j][1])
if (dst[x]+w[j][1]<dst[son[j][1]]){
dst[son[j][1]]=dst[x]+w[j][1];
if (!vis[son[j][1]]){
til=(til+1)%maxn;
que[til]=son[j][1];vis[son[j][1]]=1;
}
}
}
}
void A_star(){
heap.push((jz){s,0});
while (!heap.empty()){
jz x=heap.top();heap.pop();
if (x.x==t&&++num==k){printf("%d\n",x.w);break;}
for (int j=lnk[x.x][0];j;j=nxt[j][0]) heap.push((jz){son[j][0],x.w+w[j][0]});
}
}
int main(){
freopen("exam.in","r",stdin);
freopen("exam.out","w",stdout);
n=_read();m=_read();
for (int i=1;i<=m;i++){
int x=_read(),y=_read(),z=_read();
add(0,x,y,z);add(1,y,x,z);
}
s=_read();t=_read();k=_read();
if (s==t) k++;spfa();A_star();
if (num<k) printf("-1\n");
return 0;
}