POJ 1511 Invitation Cards(链式前向星,dij,反向建边)

题目链接

题目大意

  给\(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\n", ans);
        for (int i = 0; i<=n; ++i) h[i] = rh[i] = 0;
        tot = 0;
    }
    return 0;
}
posted @ 2020-04-22 11:00  shuitiangong  阅读(171)  评论(0编辑  收藏  举报