POJ 2449 Remmarguts' Date A*算法

题目大意

给定 n个点 m条边 给定起点终点和k
求起点到终点的第k短的路径是多少 没有就输出-1

样例

Sample Input
2 2
1 2 5
2 1 4
1 2 2
Sample Output
14

思路

        根据估价函数的设计准则,在第K短路中从x到T的估计距离f(x)应该不大于第K短路中从x到T的实际距离g(x)。 于是,我们可以把估价函数f(x) 定为从某个点到T的最短路长度,这样不但能保证f(x)≤g(x),还能顺应g(x) 的实际变化趋势,最终我们得到了以下A*算法:

1.预处理出各个节点x到终点T的最短路长度f(x) 一这等价于在反向图上T为起点求解单源最短路径问题,可以在0((N + M) log(N + M))的时间内完成。

2.建立一个二叉堆,存储些二元组(x, dist+f(x) ), 其中x为节点编号,dist表示从S到x当前走过的距离。起初堆中只有(S,0 + f(0))。

3.从二叉堆中取出dist +f(x)值最小的二元组(x,dist +(f(x) ),然后沿着从x出发的每条边(x,y)进行扩展。如果节点y被取出的次数尚未达到K,就把新的二元组(y,dist + length(x,y) + f(y))插入堆中。

4.重复第2~3步,直至第K次取出包含终点T的二元组,此时二元组中的dist值就是从S到T的第K短路。

A_star 算法的复杂度上界与优先队列BFS相同。不过因为估价函数的作用,图中很多节点访问次数都远小于K,上述A* 算法已经能够比较快速地求出结果.

代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cstdio> 
using namespace std;
const int N = 2010, M = 200010;
int ne[M], dis[N], head[N], rhead[N], e[M], w[M], len;
struct node{
	int first, second;
	bool operator<(const node &x) const{
		return first > x.first;
	}
};
struct node2{
	int a, b, c;
	bool operator<(const node2 &x) const{
		return a > x.a;
	}
};
int n, m, S, T, K;
int vis[N];
void add(int *h, int u, int v, int z){
	e[len] = v;
	w[len] = z;
	ne[len] = h[u];
	h[u] = len++;
}
void dijkstra(){
	memset(dis, 0x3f, sizeof dis);
	priority_queue<node> q;
	q.push({0, T});
	dis[T] = 0;
	while(q.size()){
		node t = q.top();
		q.pop();
		int u = t.second;
		if(vis[u]) continue;
		vis[u] = 1;
		for(int i = rhead[u]; ~i; i = ne[i]){
			int v = e[i];
			if(dis[v] > dis[u] + w[i]){
				dis[v] = dis[u] + w[i];
				q.push({dis[v], v});
			}
		}
	}
}
int a_star(){
	memset(vis, 0, sizeof vis);
	priority_queue<node2> q;
	q.push({dis[S], 0, S});
	while(q.size()){
		node2 t = q.top();
		q.pop();
		int u = t.c;
		int distance = t.b;
		vis[u]++;
		if(u == T && vis[u] == K) return distance;
		for(int i = head[u]; ~i; i = ne[i]){
			int v = e[i];
			q.push({dis[v] + distance + w[i], distance + w[i], v});
		}
	}
	return -1;
}
int main(){
	scanf("%d%d", &n, &m);
	memset(head, -1, sizeof head);
	memset(rhead, -1, sizeof rhead);
	for(int i = 0; i < m; i++){
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		add(head, a, b, c);
		add(rhead, b, a, c);
	}
	scanf("%d%d%d", &S, &T, &K);
	if(S == T) K++;
	dijkstra();
	printf("%d\n", a_star());
	
	return 0;
} 
发布了54 篇原创文章 · 获赞 155 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_45432665/article/details/104132003
今日推荐