这可爱的问题,呵呵
启发式搜索的一大旗舰问题
要弄懂它,你先去复习一下可爱的spfa吧…
当然,不怕浪费时间floyd也行
总之能求出单源最短路就行
↓↓复习完的看这里(☄⊙ω⊙)☄↓↓
题目顾名思义,就是求第k短的路径
我们的启发函数该怎么写呢
这是一个不太深奥的问题
f=g+h;
g我们就当作到当前点已经过的路程
h就依然延续以前的想法取当前点到终点的最短距离
那么我们就可以用spfa预处理一个h[i]数组记录终点到第i个点的距离
那么说明一下大概思路
用启发式搜索搜索最短路,但当到达终点时不停止
直到第k次到达终点,就是要求的第k短路
注意: 当起点与终点相同时,由于长度为0没有意义所以第k+1短路为所求
示范:以1节点为起点,n节点为终点(我没判负环φ(゜▽゜*)♪ )
#include <cstdio>
#include <queue>
using namespace std;
typedef long long ll;
const ll inf=1000000000000000000ll;
struct edge1
{
int to,next;
ll len;
}da1[100001],da2[100001];
struct edge2
{
int to;
ll g,f;
bool operator <(const edge2 &s)const
{
if(f==s.f)
return g>s.g;
return f>s.f;
}
edge2(){}
};
int head1[10001],head2[10001],cnt[10001];
ll h[10001];
bool v[10001];
int n,r,k,idx,ide;
queue <int> q;
priority_queue <edge2> Q;
void add1(int x,int y,ll z)
{
da1[++idx].to=y;
da1[idx].len=z;
da1[idx].next=head1[x];
head1[x]=idx;
return ;
}
void add2(int x,int y,ll z)
{
da2[++ide].to=y;
da2[ide].len=z;
da2[ide].next=head2[x];
head2[x]=ide;
return ;
}
void spfa()
{
for(int i=0;i<n;i++)
h[i]=inf;
q.push(n);
v[n]=true;
cnt[n]++;
while(!q.empty())
{
int tmp=q.front();
q.pop();
v[tmp]=false;
for(int i=head2[tmp];i;i=da2[i].next)
{
int tp=da2[i].to;
if(h[tp]>h[tmp]+da2[i].len)
{
h[tp]=h[tmp]+da2[i].len;
if(!v[tp])
{
q.push(tp);
v[tp]=true;
}
if(++cnt[tp]>n) return ;
}
}
}
return ;
}
ll A_s()
{
edge2 tmp;
if(n==1)
k++;
int cnt=0,l;
tmp.to=1;
tmp.g=0;
tmp.f=tmp.g+h[tmp.to];
Q.push(tmp);
while(!Q.empty())
{
tmp=Q.top();
Q.pop();
if(tmp.to==n)
{
int tp=tmp.g;
if(tp!=l)
{
l=tp;
cnt++;
}
}
if(cnt==k)
return tmp.g;
for(int i=head1[tmp.to];i;i=da1[i].next)
{
edge2 tp;
tp.to=da1[i].to;
tp.g=tmp.g+da1[i].len;
tp.f=tp.g+h[tp.to];
Q.push(tp);
}
}
return -1;
}
int main()
{
scanf("%d%d%d",&n,&r,&k);
for(int i=1;i<=r;i++)
{
int a,b;
ll c;
scanf("%d%d%lld",&a,&b,&c);
add1(a,b,c);
add2(b,a,c);
}
spfa();
printf("%lld",A_s());
return 0;
}