http://codeforces.com/contest/1343/problem/E

给定一个无向图,n个顶点,m条边,以及长度为m的数组(边权),保证每对顶点之间至少有一条路径;

mike计划从顶点a到顶点b再到顶点c,同一个顶点可以访问多次,每条边有一个边权,问怎样分配边权才能使mike走过的路的边权和最小,重复走过的路重复算。

求最小边权和。

思路:

代码如下:

#include <bits/stdc++.h>
using namespace std;
const int MAXN=5e5+5;
const int mod=1e9+7;
typedef long long ll;
const int inf=0x3f3f3f3f;
const long long INF=0x3f3f3f3f3f3f3f3f;
vector<int>g[MAXN];
ll w[MAXN],sum[MAXN];
int d[5][MAXN];
void bfs(int u,int t)
{
    queue<int>q;
    q.push(u);
    d[t][u]=0;
    while(!q.empty())
    {
        int v=q.front();
        q.pop();
        for(auto to:g[v])
        {
            if(d[t][to]!=-1)continue;
            d[t][to]=d[t][v]+1;
            q.push(to);
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m,a,b,c;
        scanf("%d%d%d%d%d",&n,&m,&a,&b,&c);
        for(int i=1;i<=m;i++)scanf("%lld",&w[i]);

        for(int i=1;i<=n+10;i++)d[0][i]=-1,d[1][i]=-1,d[2][i]=-1,sum[i]=0,g[i].clear();//初始化

        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            g[v].push_back(u);
            g[u].push_back(v);
        }

        sort(w+1,w+1+m);
        for(int i=1;i<=m;i++)sum[i]=sum[i-1]+w[i];

        bfs(a,0);//a->x
        bfs(b,1);//x->b || b->x
        bfs(c,2);//x->c

        ll ans=INF;
        for(int i=1;i<=n;i++)
        {
            if(d[0][i]+d[1][i]+d[2][i]>m)continue;//超过m时,sum数组越界,前缀和出现问题
            ans=min(ans,sum[d[1][i]]+sum[d[0][i]+d[1][i]+d[2][i]]);
        }
        printf("%lld\n",ans);
    }

    return 0;
}
View Code

 

posted on 2020-04-23 01:33  MZRONG  阅读(184)  评论(0编辑  收藏  举报