[CF1343E] Weights Distributing

Description

给定无向图和一个权值多重集,用它给无向图分配边权,要求是全排列,求路径 (a o b o c) 最短长度。

Solution

考虑到 (a o b)(b o c) 可能有一段重复的 (b - d),枚举 (d),这样只需求出 (a o d, d o b, b o d, d o c) 的最小值

设对某个 (d)(a-d,b-d,c-d) 长度分别为 (x,y,z),则我们会将最小的 (y) 个边权分配给 (b-d),剩余中最小的 (x+z) 个分配给 (a-d,c-d),因此可以在 (O(1)) 中计算出长度,故时间复杂度为 (O(n))

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 200005;
const int dbg = 0;

vector <int> g[N];
int p[N],dis[3][N],vis[N],t1,t2,n,m,a,b,c;

void bfs(int v0,int id)
{
    queue <int> que;
    que.push(v0);
    dis[id][v0]=0;
    while(!que.empty())
    {
        int p=que.front();
        que.pop();
        for(int q:g[p])
        {
            if(dis[id][q]>dis[id][p]+1)
            {
                dis[id][q]=dis[id][p]+1;
                que.push(q);
            }
        }
    }
}

void solve()
{
    cin>>n>>m>>a>>b>>c;
    for(int i=1;i<=m;i++)
    {
        cin>>p[i];
    }
    for(int i=1;i<=m;i++)
    {
        cin>>t1>>t2;
        g[t1].push_back(t2);
        g[t2].push_back(t1);
    }
    for(int i=1;i<=n;i++)
    {
        dis[0][i]=dis[1][i]=dis[2][i]=1e9;
    }
    dis[0][a]=dis[1][b]=dis[2][c]=0;
    for(int i=1;i<=n;i++)
    {
        vis[i]=0;
    }
    bfs(a,0);
    for(int i=1;i<=n;i++)
    {
        vis[i]=0;
    }
    bfs(b,1);
    for(int i=1;i<=n;i++)
    {
        vis[i]=0;
    }
    bfs(c,2);
    sort(p+1,p+m+1);
    int ans=1e18;
    int *da=dis[0],*db=dis[1],*dc=dis[2];
    for(int i=1;i<=m;i++)
    {
        p[i]+=p[i-1];
    }
    if(dbg)
    {
        cout<<"sum seq: ";
        for(int i=1;i<=m;i++)
        {
            cout<<p[i]<<" ";
        }
        cout<<endl;
    }
    int *sum=p;
    for(int i=1;i<=n;i++)
    {
        int x=da[i],y=db[i],z=dc[i];
        if(dbg)
        {
            cout<<" i="<<i<<" x,y,z="<<x<<y<<z<<endl;
        }
        if(x+y+z>m) continue;
        int tmp=0;
        tmp+=sum[x+y+z]+sum[y];
        if(dbg)
        {
            cout<<"  "<<sum[x+y+z]<<"+"<<sum[y]<<"="<<tmp<<endl;
        }
        ans=min(ans,tmp);
    }
    cout<<ans<<endl;
    for(int i=1;i<=n;i++)
    {
        g[i].clear();
        p[i]=0;
    }
}

signed main()
{
    int t;
    cin>>t;
    while(t--)
    {
        solve();
    }
}

原文地址:https://www.cnblogs.com/mollnn/p/13594381.html