题目传送门:
http://poj.org/problem?id=2449
题目简述:
给定
N
N
N点,
M
M
M边,求
S
S
S到
T
T
T的第
k
k
k短路的长度,允许重复经过点或边。
其实,题意上不允许不走,即长度为0不属于一条路径。
题解:
根据
A
s
t
a
r
Astar
Astar,我们主要是通过
f
[
i
]
f[i]
f[i],即预测未来到达终点要消耗的代价,以及现在已经消耗的代价
h
[
i
]
h[i]
h[i] ,令
c
[
i
]
=
f
[
i
]
+
h
[
i
]
c[i]=f[i]+h[i]
c[i]=f[i]+h[i],利用优先队列,优先扩展
c
[
]
c[]
c[]较小的点,这就是
A
s
t
a
r
Astar
Astar的精髓。
A
s
t
a
r
A_star
Astar算法详情可看《算法竞赛进阶指南——李煜东》
那么本题可将当前点到终点的最短路作为
f
[
]
f[]
f[],预处理为一次
s
p
f
a
spfa
spfa,我们知道,在BFS中,某状态第一次从堆中被取出时,就得到了起点到它的最小代价。由数学归纳法:“当第i次从堆中取出节点
x
x
x时,对应的代价即为
S
S
S到
x
x
x的第i短路”
上代码:
#include<cstdio>
#include<queue>
using namespace std;
int f[1010],first1[1010],first2[1010],len1=0,len2=0,n,m,k;
struct bian1{int y,next,c;}a[200100];
struct bian2{int y,next,c;}b[200100];
//f[i]表示估值函数,存i到终点的最短路保证了f[i]<=g[i](其他路径)
void ins1(int x,int y,int c)
{
len1++; a[len1].y=y; a[len1].c=c;
a[len1].next=first1[x]; first1[x]=len1;
}
void ins2(int x,int y,int c)
{
len2++; b[len2].y=y; b[len2].c=c;
b[len2].next=first2[x]; first2[x]=len2;
}
queue<int> q;
int v[1010],st,ed;
void spfa()
{
for(int i=1;i<=n;i++) f[i]=999999999;
q.push(ed);
f[ed]=0; v[ed]=1;
while(!q.empty())
{
int x=q.front(); q.pop(); v[x]=0;
for(int i=first1[x];i>0;i=a[i].next)
{
int y=a[i].y;
if(f[y]>f[x]+a[i].c)
{
f[y]=f[x]+a[i].c;
if(!v[y])
{
v[y]=1;
q.push(y);
}
}
}
}
}
struct node{
int id,c,h;//c表f+h h表已走
friend bool operator < (const node &x,const node &y)
{ if(x.c==y.c) return x.h>y.h; return x.c>y.c; }
};
node cur;
priority_queue<node> p;
int a_star()
{
if(st==ed) k++;//不允许不走
if(f[st]==999999999) return -1;
for(int i=1;i<=n;i++) v[i]=0;
cur.id=st;cur.c=f[st],cur.h=0;
p.push(cur);
node x;
while(!p.empty())
{
x=p.top(); p.pop();
v[x.id]++; if(v[ed]==k) return x.c;//从堆取出
for(int i=first2[x.id];i>0;i=b[i].next)
{
int y=b[i].y;
if(v[y]<k)
{
cur.id=y,cur.c=x.h+f[y]+b[i].c,cur.h=x.h+b[i].c;
p.push(cur);
}
}
}return -1;
}
int main()
{
int x,y,c;
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&x,&y,&c);
ins1(y,x,c); ins2(x,y,c);
}scanf("%d %d %d",&st,&ed,&k);
spfa(); //for(int i=1;i<=n;i++) printf("%d ",f[i]);
printf("%d",a_star());
return 0;
}