版权声明:作为一个蒟蒻,转载时请通知我这个蒟蒻 https://blog.csdn.net/zyszlb2003/article/details/89433892
欢迎大家访问我的老师的OJ———caioj.cn
题面描述
给定
个点,
条有向边,求第
短路。
注意:若出发点与结束点为同一点,则一定要从出发点跑出去,再跑回来,才算最短路
思路
这道题如果直接优先队列跑的话,最坏时间复杂度为
,因为我们要跑
次路径。
现提供
做法:
所谓
,用人话描述就是目光要放长远,脚步要够坚定,它好比有高人带着你刷副本似的,少走弯路。
比起普通优先队列,
多了一个估价函数
,为了保证最优解,
要满足一个基本准则
- 设当前状态 到目标状态所需代价的估计值为
- 实际所需价值为 .
- 对于任意的 ,应该有
这种带有估计函数的优先队列BFS就称为
.只要保证
,A*就一定能在目标状态第一次从堆中取出时得到最优解,并且在搜索过程中每个状态只需要被拓展一次。
下面给出简要证明:
设当前状态
并不是最优解,
则
的“当前代价”+
当前处在未来最优路径上的
的“代价“+
,所以
先拓展,
则被忽略。
第K短路则运用了 的排除多余状态与优先队列 ,第几次取出 ,即求到第几短路的性质来解决问题, 主要起优化作用。
先反向求从 跑到 的最短路,得到估价函数
后正常BFS即可。
代码
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int N=1e3+10;
const int inf=0x3f3f3f3f;
const int M=1e5+10;
struct edge{int x,y,d,next;}a[M],b[M];int len,last1[N],last2[N];
void ins(int x,int y,int d)
{
a[++len].x=x,a[len].y=y;a[len].d=d;a[len].next=last1[x];last1[x]=len;
b[len].x=y;b[len].y=x;b[len].d=d;b[len].next=last2[y];last2[y]=len;
}
struct nde
{
int x,d;
nde(){}
nde(int x,int d):x(x),d(d){}
bool operator <(const nde a)const{return d>a.d;}
};
int f[N];bool v[N];int st,ed;
void dijk_p()
{
priority_queue<nde>q;
memset(f,0x3f,sizeof(f));memset(v,false,sizeof(v));
q.push(nde(ed,0));f[ed]=0;
while(!q.empty())
{
nde t=q.top();q.pop();
int x=t.x;if(v[x])continue;
v[x]=true;
for(int k=last2[x];k;k=b[k].next)
{
int y=b[k].y;
if(f[y]>f[x]+b[k].d)
{
f[y]=f[x]+b[k].d;
q.push(nde(y,f[y]));
}
}
}
}
struct node
{
int x,d,f;
node(){}
node(int x,int d,int f):x(x),d(d),f(f){}
bool operator <(const node a)const{return f==a.f?d>a.d:f>a.f;}
};
int kl;
void dijk_AS()
{
priority_queue<node>q;int cnt=0;
if(f[st]==inf){puts("-1");return ;}
q.push(node(st,0,f[st]));
while(!q.empty())
{
node t=q.top();q.pop();
if(t.x==ed)cnt++;
if(kl==cnt){printf("%d\n",t.d);return ;}
int x=t.x;
for(int k=last1[x];k;k=a[k].next)
{
int y=a[k].y;
int d=t.d+a[k].d;
q.push(node(y,d,d+f[y]));
}
}
puts("-1");
}
int main()
{
int n,m;len=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){int x,y, d;scanf("%d%d%d",&x,&y,&d);ins(x,y,d);}
scanf("%d%d%d",&st,&ed,&kl);if(st==ed)kl++;
dijk_p();
dijk_AS();
return 0;
}