题目大意
输出一张有向带权图前k短路的长度
思路分析
这是道k短路板子题
我们可以用Astar算法来实现它
OIwiki相关算法的网页
简单来讲,Astar定义了一个估值函数f(x)=g(x)+h(x) g(x)表示由起点到达x点的路程(不一定是最短路),而h(x)则是终点到x点的最短路程
这个估值函数可以预估从该点到终点的最短路径。
在搜索中,Astar可以帮助剪枝
而在求k短路中,Astar则可以保证访问终点路径的次序与路径长度从小到大的次序相同
每次取最优f[x]进行拓展,必然可以保证较短的路径先被拓展
因此可以用Astar算法算k短路
终点被第几次访问的代价就是第几短路
代码实现方面,先从终点跑一遍单源最短路,然后从起点开始搜索,用cnt记录访问终点的次数,如果次数为k,结束搜索;如果搜索完后发现cnt不足k,再补-1输出
AC代码
#include<bits/stdc++.h>
#define N 10010
using namespace std;
struct node{int v,w;};
struct cmp{
bool operator()(node a,node b){return a.w>b.w;}
};
vector<node>g[N],rg[N];
int n,m,k,H[N];
void dijkstra(){
memset(H,0x3f,sizeof(H));
queue<int>q;
q.push(1);
H[1]=0;
while(!q.empty()){
int u=q.front();
q.pop();
for(node t:rg[u]){
if(H[t.v]>H[u]+t.w){
H[t.v]=H[u]+t.w;
q.push(t.v);
}
}
}
}
void Astar(){
priority_queue<node,vector<node>,cmp>pq;//实际上,优先队列不必要重载运算符号
pq.push({n,H[n]});
int cnt=0;
while(!pq.empty()){
node tep=pq.top();
pq.pop();
int u=tep.v,w=tep.w;
if(u==1){
cnt++;
printf("%d\n",w);
if(cnt==k)return;
}
for(auto t:g[u])pq.push({t.v,w+t.w-H[u]+H[t.v]});
}
for(;cnt<k;cnt++)printf("-1\n");
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1,u,v,d;i<=m;i++){
scanf("%d%d%d",&u,&v,&d);
g[u].push_back({v,d});
rg[v].push_back({u,d});//反向建边求以n点出发的单源最短路
}
dijkstra();
Astar();
}