【Educational Codeforces Round 38】D. Buy a Ticket 堆优化Dijkstra

题意

给定一张无向图,对每个点$i\in S$求$\min_{j\in S} {2\times d(i,j)+a_j}$


考虑多源多汇最短路会超时,换个角度考虑每个$j$,如果$j=i$,那么答案为$a_i$,如果有更优的方案,那么为$i$到$j$的一条路径加上$a_j$,将这个过程看成两条路径,并且将$a_j$独立为一条路径,就得到最短路算法中的松弛操作,可以建立一个超级源点,连向各点,边权为$a_i$,那么从源点跑一遍最短路之后就是每个点所求答案

时间复杂度$O(n\log n)$

代码

#include <bits/stdc++.h>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long LL;
typedef pair<LL, int> pli;
const int N = 200010;
int cnt, head[N], nxt[3 * N], to[3 * N];
LL val[3 * N];
inline void add_edge(int u, int v, LL w) {
    to[cnt] = v; val[cnt] = w; nxt[cnt] = head[u]; head[u] = cnt++;
}
int vis[N];
LL dis[N];
int n, m, x, y;
LL z;
inline void dijkstra(int s) {
    priority_queue<pli, vector<pli >, greater<pli > > pq;
    memset(vis, 0, sizeof(vis));
    memset(dis,0x3f,sizeof(dis)); dis[s] = 0;
    pq.push(make_pair(dis[s], s));
    while(!pq.empty()) {
        pli now = pq.top(); pq.pop();
        int u = now.second; if(vis[u]) continue; vis[u] = 1;
        for(int i = head[u]; ~i; i = nxt[i]) {
            int v = to[i];
            if(dis[v] > dis[u] + val[i]) {
                dis[v] = dis[u] + val[i];
                pq.push(make_pair(dis[v], v));
            }
        }
    }
}
int main() {
    cnt = 0; memset(head, -1, sizeof(head));
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; ++i) {
        scanf("%d%d%I64d", &x, &y, &z);
        add_edge(x, y, 2 * z); add_edge(y, x, 2 * z);
    }
    for(int i = 1; i <= n; ++i) {
        scanf("%I64d", &z);
        add_edge(0, i, z);
    }
    dijkstra(0);
    for(int i = 1; i <= n; ++i) {
        printf("%I64d%c", dis[i], i == n ? '\n' : ' ');
    }
    return 0;
}
posted @ 2018-02-20 17:01  Ogiso_Setsuna  阅读(97)  评论(0编辑  收藏  举报