2019ccpc网络赛 HDU - 6705 path 贪心跑第k小的路径长度

题目链接:https://vjudge.net/problem/HDU-6705

题解:建立源点 汇点 跑A*,到最后也一直超内存也真是菜到家了,A*时间空间怎么也得n^2,这个题原来是个贪心。。。。

官方题解:

先把每条边以 形式放进堆,堆按路径权值从小到大排序,然后每次取出堆顶,用v的出边扩展 新的路径。但是一个点的出度可能会非常大(如菊花图),可以发现,将出边排序之后,每次只需要扩 展当前点最小的出边,和扩展到当前点的边的下一条边即可。堆中需要记录当前结点,当前距离,上一 节点距离,扩展到当前节点时下一条应该扩展的边。(注意,如果一次性扩展当前点连出去的所有权值 相同的边,是会TLE的,实际上也是没有必要的。)
 

#include 
using namespace std;
typedef long long ll;
const int N = 50010;
struct node {
	int from, to;
	ll d;
	int p;
	node (int from_ = 0, int to_ = 0, ll d_ = 0, int p_ =  0) {
		from = from_;
		to = to_;
		d = d_; 
		p = p_;
	}
	bool operator <(const node &b)const {
		return d > b.d;
	}
}; 
struct edge {
	int from, to, d;
	edge(int from_, int to_, int d_) {
		from = from_;
		to = to_;
		d = d_; 
	}
	bool operator <(const edge &b)const{
		return d < b.d; 
	}
};
vector v[N];
int n, m, k;
int qq[N];
ll ans[N];
int main() {
	int T;
	int from, to, d;
	int mx;
	int num;
	scanf("%d", &T);
	while(T--) {
		priority_queue q;
		node now;
		scanf("%d %d %d", &n, &m, &k);
		for(int i = 1; i <= n; i++) v[i].clear();
		for(int i = 1; i <= m; i++) {
			scanf("%d %d %d", &from, &to, &d);
			v[from].push_back(edge(from, to, d));
		}
		mx = 0;
		for(int i = 1; i <= k; i++) scanf("%d", &qq[i]), mx = max(mx, qq[i]);
		for(int i = 1; i <= n; i++) {
			sort(v[i].begin(), v[i].end());
			if(v[i].size() ) {
				q.push(node(i, v[i][0].to, v[i][0].d, 0));
			}
		}
		num = 0;
		while(!q.empty()) {
			now = q.top(); q.pop();
			num++;
			ans[num] = now.d;
			if(num == mx) break;
			if(now.p < v[now.from].size() - 1)
				q.push(node(now.from, v[now.from][now.p + 1].to, now.d - v[now.from][now.p].d + v[now.from][now.p + 1].d, now.p + 1) );
			if(v[now.to].size())
				q.push(node(now.to, v[now.to][0].to, now.d + v[now.to][0].d, 0) );
		}
		for(int i = 1; i <= k; i++)
			printf("%lld\n", ans[qq[i]]);
	}
	return 0;
}

 

你可能感兴趣的:(贪心,最短路)