http://poj.org/problem?id=2449
根据A*
f(p)=g(p)+h(p)
g(p)就是p点到s点最短距离
h(p)就是p点到t点的距离
h(p)的求法就是将边反过来求一遍单源最短路即可。
为什么要用A*?
A*的作用就是将普通的bfs变得更加智能,我们可以通过改变h函数来达到我们希望的效果。
这道题,我们要求第K短路,那么怎么去求呢。
思路就是利用A*,将较短的路径上的点放在前面去跑。
这样我们第一次跑到终点的路径一定是最短的。
那么我们怎么去找第K短,就是将js++,继续跑,因为此时优先队列中的点都是有序的,下一次跑到终点就一定是第二短路径。
以此类推,直到第k次找到终点,就一定是第k短的。
但是要注意,如果起点与终点一样,那么开始要将js++,因为此时最短路径为它本身这个点也就是0,所以这种情况下实际上我们要找的是第k+1短路
#include<cstdio>
#include<iostream>
#include<stack>
#include<queue>
#include<cmath>
#include<cstring>
using namespace std;
int n,m;
struct node{
int v;
int nex;
int cost;
};
node eg[555555];
node reg[555555];
int hea[555555];
int rhea[555555];
int dis[555555];
bool vis[555555];
int ss[3333333];
int e=0;
struct As{
int p;
int g;
int f;
bool operator <(const As a)const{
if(f==a.f)return g>a.g;
return f>a.f;
}
};
void insert(int st,int ed,int cost)
{
eg[e].v=ed;
eg[e].cost=cost;
eg[e].nex=hea[st];
hea[st]=e;
reg[e].v=st;
reg[e].cost=cost;
reg[e].nex=rhea[ed];
rhea[ed]=e++;
}
void spfa(int st)
{
memset(dis,0x3f3f3f3f,sizeof(dis));
memset(vis,0,sizeof(vis));
int h=0;
int r=1;
ss[h]=st;
dis[st]=0;
int tt;
while(h<r)
{
tt=ss[h];
vis[tt]=0;
h++;
for(int i=rhea[tt];i!=-1;i=reg[i].nex)
{
if(dis[reg[i].v]>dis[tt]+reg[i].cost)
{
dis[reg[i].v]=dis[tt]+reg[i].cost;
if(vis[reg[i].v]==0)
{
ss[r++]=reg[i].v;
vis[reg[i].v]=1;
}
}
}
}
}
int astar(int st,int ed,int k)
{
priority_queue<As> qu;
if(st==ed)k++;
int js=0;
As t,tt;
t.p=st;
t.g=0;
t.f=t.g+dis[st];
qu.push(t);
while(!qu.empty())
{
tt=qu.top();
qu.pop();
if(tt.p==ed)
{
js++;
if(js==k)
return tt.g;
}
for(int i=hea[tt.p];i!=-1;i=eg[i].nex)
{
t.p=eg[i].v;
t.g=tt.g+eg[i].cost;
t.f=t.g+dis[eg[i].v];
qu.push(t);
}
}
return -1;
}
int main(){
while(scanf("%d%d", &n, &m) != EOF)
{
e=0;
int st,ed,cost;
int s,t,k;
memset(hea,-1,sizeof(hea));
memset(rhea,-1,sizeof(rhea));
for(int i=0;i<m;i++)
{
cin>>st>>ed>>cost;
insert(st,ed,cost);
}
cin>>s>>t>>k;
spfa(t);
//for(int i=1;i<=n;i++)
//cout<<dis[i]<<" "<<endl;
if(dis[s]==0x3f3f3f3f)
{
cout<<"-1"<<endl;
}
else
cout<<astar(s,t,k)<<endl;
}
return 0;
}