题目大意
给(n)个点和(m)条单向边,求从(1)号出发再从(1)号点回来的最短路。
具体实现
从(1)号点出发到各个点就是裸的最短路,而从各个点回到(1)号点,可以反向建边求(1)号点到各个点的最短路。但是这题用(vector)存边会卡常数,建议用邻接表(or)链式前向星。
代码
const int maxn = 1e6+10;
struct E {
int v, w, nxt;
} e[maxn<<1];
int n, m, tot, h[maxn], rh[maxn];
ll d[maxn];
void add(int a, int b, int c, int h[]) {
++tot;
e[tot].v = b, e[tot].w = c, e[tot].nxt = h[a];
h[a] = tot;
}
ll dij(int h[]) {
for (int i = 0; i<=n; ++i) d[i] = LLONG_MAX/10;
d[1] = 0;
ll res = 0;
priority_queue<Pii, vector<Pii>, greater<Pii> > pq;
pq.push(Pii(0,1));
while(!pq.empty()) {
Pii t = pq.top(); pq.pop();
int w = t.first, u = t.second;
if (d[u]<w) continue;
res += w;
for (int i = h[u]; i; i = e[i].nxt) {
int v = e[i].v;
if (d[v] > w+e[i].w) {
d[v] = w+e[i].w;
pq.push(Pii(d[v],v));
}
}
}
return res;
}
int main(void) {
int t; scanf("%d", &t);
while(t--) {
scanf("%d%d", &n, &m);
for (int i = 0, a, b, c; i<m; ++i) {
scanf("%d%d%d", &a, &b, &c);
add(a, b, c, h);
add(b, a, c, rh);
}
ll ans = dij(h); ans += dij(rh);
printf("%lld
", ans);
for (int i = 0; i<=n; ++i) h[i] = rh[i] = 0;
tot = 0;
}
return 0;
}