E. Weights Distributing(思路 + 最短路)

E. Weights Distributing

题目链接
在这里插入图片描述
在这里插入图片描述

思路

  • 题意:给了我们一个有n个节点m无权值的边形成的无向图,又给了我们 m个权值,我们要把这个m个权值一一分配的图中的m条边上,问一个人从节点a出发,经过节点b,最终到达节点c,经过我合理分配m条边的权值之后,整个过程所需要的最小边权和是多少?

  • 思路

  1. 首先容易看出来的最后的边权和与走的边数有关,那么走的边越少且a->b 与 b->c这两个过程中重复的路径越多越好(因为这样我们可以把重复的边安排为权值较小的边)
  2. 我们考虑两种情况:(总共出现的情况也就这两种:路径有、无重叠)
    1. 如果 a – b – c ,这个三个节点在同一条路径上,这个时候a->b 与 b->c这两个过程是没用重复的路径的,那么这个时候我们将a->b、b-c这个两个过程的最短路的值相加设为k,那么答案就是 将前k小的权值加起来
    2. 第二种情况,我们考虑两条路径之间有重叠的部分(说明a->b、b->c 这两个过程都经过了相同的某个节点设为x),那么这个时候的过程可以看为:a—>x—>b—>x—>c,这个时候由于b—>x被重复的经过所以我们给b—x上的边分配最小的权值,,,这个时候我们还用考虑 x选择哪个节点好?,这个解决方案就是从1-n枚举x 的值;我们特殊考虑 x == b 是这个时候的路线变成的a—>b—>c 这个路成变成了:第一种情况时的路线了,说明第二种情况是包含第一种的情况的
  3. 因为第二种情况包含第一种情况,所以我们只需要考虑第二种情况,我们设: d a [ x ] , d b [ x ] , d c [ x ] da[x],db[x],dc[x] ,分别为 a , b , c a,b,c 到节点x的最短路,我们设 p r e f [ i ] pref[i] 前i小的边权的前缀和,,,第二种情况的过程为: a—>x—>b—>x—>c,我们可将其拆分成四段路分为两组:b-->xa--x,b--x,x--c,对于第一组由于b-->x重复走了两次我们分配给的这里面的边的权值尽可能的小 为: p r e f [ d b [ x ] ] pref[db[x]] ;对与第二组中的边,b--x中的边在第一组已经被分配好权值,对于接下a-->x,x-->c来的边我们只需要在所有没有分配的权值中选择较小的给 分配上权值就行了 :第二组的边权和为: p r e f [ d a [ x ] + d b [ x ] + d c [ x ] ] pref[da[x]+db[x]+dc[x]] ,最终答案就是两组 边权和相加

代码

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>

using namespace std;
const int INF = 0x3f3f3f3f;
vector<vector<int> > g;

void bfs(int s, vector<int> &dis)
{
    dis[s] = 0;
    queue<int> q;
    q.push(s);  
    while(! q.empty())
    {
        int u = q.front();
        q.pop();
        
        for(auto v : g[u])
        {
            if(dis[v] == INF)
            {
                dis[v] = dis[u] + 1;
                q.push(v);
            }
        }
    }
}



int main() {
    /* freopen("A.txt", "r", stdin); */
    /* freopen("Ans.txt", "w", stdout); */
    int t;
    scanf("%d", &t);
    while(t --)
    {
        int n, m, a, b, c;
        scanf("%d %d %d %d %d", &n, &m, &a, &b, &c);
        a --, b --, c --;
        vector<int> p(m);
        for(auto &x : p)
            scanf("%d", &x);
        sort(p.begin(), p.end());
        vector<long long> pref(m+1);
        for(int i = 0; i < m; i ++)
            pref[i+1] = pref[i] + p[i];

        g = vector<vector<int> > (n);
        int u, v;
        for(int i = 0; i < m; i ++)
        {
            scanf("%d %d", &u, &v);
            u --, v --;
            g[u].push_back(v);
            g[v].push_back(u);
        }
            
        vector<int> da(n, INF), db(n, INF), dc(n, INF);
        bfs(a, da);
        bfs(b, db);
        bfs(c, dc);
        long long ans = 1e18;
        for(int i = 0; i < n; i ++)
        {
            if(da[i] + db[i] + dc[i] > m) continue;
            ans = min(ans, pref[db[i]] + pref[db[i] + da[i] + dc[i]]);
        }
        printf("%lld\n", ans);
    }




    return 0;
}
原创文章 220 获赞 292 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_34261446/article/details/105753266