A*搜索主要思想:f[i] = g[i] + h[i] 。f[i] 即为所求,g[i] 表示已走过距离,h[i] 表示距离终点的距离。在优先队列中,能尽量把符合条件的方案提前,优化搜索。
对于这道题,先反向建边,求出每个点到终点的最短距离。
再正向搜索,所要记录的内容有:当前节点,已走过了距离,已走过的距离+这点到终点的距离。
每次把与这点相连的下一个点放入队列,直到第k次取出终点,便求出第k短路。
注意:自己到自己距离为0不算(坑爹)。
#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define inf 100010
#define INF 0xffffff
struct node1
{
int to,next,val;
};
node1 edge1[inf],edge2[inf];
int cnt1;
int head1[1010];
void add1(int f,int t,int v)
{
edge1[cnt1].to=t;
edge1[cnt1].val=v;
edge1[cnt1].next=head1[f];
head1[f]=cnt1++;
}
int cnt2;
int head2[1010];
void add2(int f,int t,int v)
{
edge2[cnt2].to=t;
edge2[cnt2].val=v;
edge2[cnt2].next=head2[f];
head2[f]=cnt2++;
}
int n,m,s,t,k;
int vis[1010],dis[1010];
void spfa()
{
for(int i=1;i<=n;i++)
{
dis[i]=INF;
vis[i]=0;
}
queue<int>Q;
Q.push(t);
dis[t]=0;
vis[t]++;
while(!Q.empty())
{
int u=Q.front();
Q.pop();
vis[u]--;
if(vis[u]>n)return ;
for(int i=head1[u];i!=-1;i=edge1[i].next)
{
int v=edge1[i].to;
if(dis[v]>dis[u]+edge1[i].val)
{
dis[v]=dis[u]+edge1[i].val;
if(vis[v]==0)
{
vis[v]++;
Q.push(v);
}
}
}
}
return ;
}
struct node
{
int i,len,sum;
bool operator<(const node &r ) const //这个必须放在里面,尽管我不知道为什么。。。就因为这个,我把poj刷屏了。。。坑了爹一晚上啊!!!
{
if(r.sum==sum)
return r.len<len;
return r.sum<sum;
}
};
int cnt;
int bfs()
{
priority_queue<node>QQ;
if(s==t)k++;//因为自己到自己距离为0不算
if(dis[s]==INF)return -1;
node st;
st.i=s;
st.len=0;
st.sum=dis[s];
QQ.push(st);
while(!QQ.empty())
{
node u;
u=QQ.top();
QQ.pop();
if(u.i==t)
{
cnt++;
}
if(cnt==k)
{
return u.len;
}
for(int j=head2[u.i];j!=-1;j=edge2[j].next)
{
node v;
v.i=edge2[j].to;
v.len=u.len+edge2[j].val;
v.sum=v.len+dis[v.i];
QQ.push(v);
}
}
return -1;
}
int main()
{
memset(head1,-1,sizeof(head1));
memset(head2,-1,sizeof(head2));
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
add1(b,a,c);
add2(a,b,c);
}
scanf("%d %d %d",&s,&t,&k);
spfa();
printf("%d\n",bfs());
}