zoukankan      html  css  js  c++  java
  • CodeForces 1343E Weights Distributing

    题意

    多组样例

    给定(n,m,a,b,c),给定一个长度为(m)的数组(p[]),给定(m)条边,构成一个(n)个点(m)条边的无向图,(Mike)想要从(a)走到(b),再从(b)走到(c),你可以在他从(a)出发前将(p[])中的值分配到(m)条边上,问(Mike)最少走多少路程

    分析

    我们先将所有边的权值赋为(1),意为两点间的最小边数为多少

    如果(a)(b)(b)(c)的最短路不重合,那就直接将两条路上的边从小到大赋值即可,问题在于有重合的部分路径

    发现(sum nleq 2cdot 10^5),我们可以枚举重合的点(i),让(Mike)走路径(a->i->b->i->c),然后求得边数,其中(i->b)的路径为(p[])中最小的几个元素,因为要走两遍,(i->a)(i->c)的的路径为剩下元素中最小的元素

    由于为无向图,(i)到三点距离即为三点到(i)距离,为表述方便,皆用(i)到三点表述

    枚举(i)肯定不能以(i)为起点求最短路,否则时间复杂度太高,则可以以三点求最短路,然后枚举(i)

    先计算(i->a)的边数,以(a)为起点,使用(Dijkstra)算法,再计算(i->b)的边数,以(b)为起点,使用(Dijkstra)算法,再计算(i->c)的边数,以(c)为起点,使用(Dijkstra)算法,其中不同的距离设为(disa[],disb[],disc[])

    因为是求路径权值和,可直接排序后计算前缀和(sum[])

    (i->a)的路径为(disai)(i->)的b路径为(disbi)(i->c)的路径为(disci),则答案为(sum[disai + disbi + disci] + sum[disbi])的最小值(三边总的前缀和加上(i->b)的二次计算)

    由于(i)到三点的路径不可能有重叠(否则取重叠点可使得答案更小),因此三条路径和小于(m),正好使得(disai + disbi + disci)不会超出(sum[])的范围

    #pragma GCC optimize(3, "Ofast", "inline")
    
    #include <bits/stdc++.h>
    
    #define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    #define ll long long
    #define int ll
    #define ls st<<1
    #define rs st<<1|1
    #define pii pair<int,int>
    #define rep(z, x, y) for(int z=x;z<=y;++z)
    #define com bool operator<(const node &b)
    using namespace std;
    const int maxn = (ll) 2e5 + 5;
    const int mod = (ll) 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    int T = 1;
    
    struct edge {
        int v, next, w;
    } e[maxn << 1];
    
    struct node {
        int dis, u;
    
        bool operator<(const node &b) const {
            return dis > b.dis;
        }
    };
    
    int cnt;
    int head[maxn];
    int disa[maxn];
    int disb[maxn];
    int disc[maxn];
    bool vis[maxn];
    
    void addedge(int u, int v, int w) {
        e[++cnt].next = head[u];
        e[cnt].v = v;
        e[cnt].w = w;
        head[u] = cnt;
        e[++cnt].next = head[v];
        e[cnt].v = u;
        e[cnt].w = w;
        head[v] = cnt;
    }
    
    int n, m, s;
    
    void dijkstra_a() {
        priority_queue<node> q;
        disa[s] = 0;
        node st;
        st.dis = 0;
        st.u = s;
        q.push(st);
        while (!q.empty()) {
            node u = q.top();
            q.pop();
            if (vis[u.u])
                continue;
            vis[u.u] = true;
            for (int i = head[u.u]; ~i; i = e[i].next) {
                int v = e[i].v;
                if (disa[v] > disa[u.u] + e[i].w) {
                    disa[v] = disa[u.u] + e[i].w;
                    node w;
                    w.dis = disa[v];
                    w.u = v;
                    q.push(w);
                }
            }
        }
    }
    
    void dijkstra_b() {
        priority_queue<node> q;
        disb[s] = 0;
        node st;
        st.dis = 0;
        st.u = s;
        q.push(st);
        while (!q.empty()) {
            node u = q.top();
            q.pop();
            if (vis[u.u])
                continue;
            vis[u.u] = true;
            for (int i = head[u.u]; ~i; i = e[i].next) {
                int v = e[i].v;
                if (disb[v] > disb[u.u] + e[i].w) {
                    disb[v] = disb[u.u] + e[i].w;
                    node w;
                    w.dis = disb[v];
                    w.u = v;
                    q.push(w);
                }
            }
        }
    }
    
    void dijkstra_c() {
        priority_queue<node> q;
        disc[s] = 0;
        node st;
        st.dis = 0;
        st.u = s;
        q.push(st);
        while (!q.empty()) {
            node u = q.top();
            q.pop();
            if (vis[u.u])
                continue;
            vis[u.u] = true;
            for (int i = head[u.u]; ~i; i = e[i].next) {
                int v = e[i].v;
                if (disc[v] > disc[u.u] + e[i].w) {
                    disc[v] = disc[u.u] + e[i].w;
                    node w;
                    w.dis = disc[v];
                    w.u = v;
                    q.push(w);
                }
            }
        }
    }
    
    int num[maxn], sum[maxn];
    
    void solve() {
        memset(head, -1, sizeof(head));
        cnt = 0;
        int a, b, c;
        cin >> n >> m >> a >> b >> c;
        rep(i, 1, m)cin >> num[i];
        sort(num + 1, num + 1 + m);
        rep(i, 1, m)sum[i] = sum[i - 1] + num[i];
        rep(i, 1, m) {
            int u, v;
            cin >> u >> v;
            addedge(u, v, 1);
        }
        s = a;
        rep(i, 1, n) {
            disa[i] = disb[i] = disc[i] = inf;
            vis[i] = false;
        }
        dijkstra_a();
        s = b;
        rep(i, 1, n)vis[i] = false;
        dijkstra_b();
        s = c;
        rep(i, 1, n)vis[i] = false;
        dijkstra_c();
        int ans = LLONG_MAX;
        rep(i, 1, n) {
            int disai = disa[i];
            int disbi = disb[i];
            int disci = disc[i];
            if (disai + disbi + disci > m)
                continue;
            int now = sum[disai + disbi + disci] + sum[disbi];
            ans = min(ans, now);
        }
        cout << ans << '
    ';
    }
    
    
    signed main() {
        start;
        cin >> T;
        while (T--)
            solve();
        return 0;
    }
    
  • 相关阅读:
    HDU1266 Reverse Number
    codevs1380 没有上司的舞会
    codevs1163 访问艺术馆
    codevs2144 砝码称重 2
    codevs1553 互斥的数
    codevs1230 元素查找
    codevs3118 高精度练习之除法
    codevs1245 最小的N个和
    codevs1063 合并果子
    codevs1052 地鼠游戏
  • 原文地址:https://www.cnblogs.com/F-Mu/p/12760182.html
Copyright © 2011-2022 走看看