题意
k短路
题解
A*+dijkstra
用最短路长度作为k短路的估价函数再适合不过了。恰好满足f[x]<=g[x](f是估价函数,g是实际情况)。
因为f应当是距离t的最短路,所以我们要反着跑一遍dijkstra,这样就处理好了f数组。
接下来正着跑A*。对于每个点可以的所有距离都记录下来,选择f[x]+d最小的优先遍历。
因为我们用的时优先BFS,当t第1次出队列时,一定是从s到该点的最短路径;第k次出队,则是从s到该点的k短路。
注意一个坑点:当s==t时,k++。
代码
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1010,maxm=100010;
int n,m;
int s,t,k;
struct edge
{
int x,y,c,next;
}e[maxm],fe[maxm];int len=0,last[maxn],flast[maxn];
void ins(int x,int y,int c)
{
e[++len]=(edge){x,y,c,last[x]};last[x]=len;
fe[len]=(edge){y,x,c,flast[y]};flast[y]=len;//debug len只要加一次
}
int f[maxn];//f以最短路长作为估价函数
struct F
{
int x,d;
bool operator<(F f1)const
{
return d>f1.d;
}
};
bool v[maxn];
void dijkstra()
{
priority_queue<F> q;
q.push((F){t,0});
memset(f,63,sizeof(f));f[t]=0;
memset(v,false,sizeof(v));
while(!q.empty())
{
F top=q.top();q.pop();
int x=top.x,d=top.d;
if(v[x]) continue;
v[x]=true;
for(int k=flast[x];k;k=fe[k].next)
{
int y=fe[k].y;
if(f[y]>f[x]+fe[k].c)
{
f[y]=f[x]+fe[k].c;
q.push((F){y,f[y]});
}
}
}
}
struct R
{
int x,d;//x表示点编号 d表示当前距离
bool operator<(R r1)const
{
return d+f[x]>r1.d+f[r1.x];
}
};
void Astra()
{
if(s==t) k++;//坑!!!
priority_queue<R> q;
q.push((R){s,0});
while(!q.empty())
{
R top=q.top();q.pop();
int x=top.x,d=top.d;
if(x==t)
if(k==1)
{
printf("%d\n",d);
return ;
}
else
{
k--;
}
for(int k=last[x];k;k=e[k].next)
{
int y=e[k].y;
int nd=d+e[k].c;
q.push((R){y,nd});
}
}
printf("-1\n");
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
len=0;
memset(last,0,sizeof(last));
memset(flast,0,sizeof(flast));
for(int i=1;i<=m;i++)
{
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
ins(x,y,c);
}
scanf("%d%d%d",&s,&t,&k);
dijkstra();
Astra();
}
return 0;
}