wanxue

博客园 首页 新随笔 联系 订阅 管理

题目大意

输出一张有向带权图前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();
}
posted on 2024-08-09 16:23  thelatersnow  阅读(7)  评论(0编辑  收藏  举报