题目链接:https://vjudge.net/problem/HDU-6705
题解:建立源点 汇点 跑A*,到最后也一直超内存也真是菜到家了,A*时间空间怎么也得n^2,这个题原来是个贪心。。。。
官方题解:
先把每条边以 形式放进堆,堆按路径权值从小到大排序,然后每次取出堆顶,用v的出边扩展 新的路径。但是一个点的出度可能会非常大(如菊花图),可以发现,将出边排序之后,每次只需要扩 展当前点最小的出边,和扩展到当前点的边的下一条边即可。堆中需要记录当前结点,当前距离,上一 节点距离,扩展到当前节点时下一条应该扩展的边。(注意,如果一次性扩展当前点连出去的所有权值 相同的边,是会TLE的,实际上也是没有必要的。)
#include <bits/stdc++.h>
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<edge> 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<node> 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;
}