CF1343E-Weights Distributing (最短路)

题目大意:

给定你一个由n个节点,m条边组成的图,再告诉你3个节点a,b,c和一个大小为m的数组p,

让你将p[i]赋值给每条边,使得a->b->c的路径长度最短。

链接:https://codeforces.com/contest/1343/problem/E

思路:

因为要使路径长度最短,所以边权要尽量小,所以我们先将p数组进行排序,然后预处理出他们的前缀和,

然后我们分别求出每个点到a的最短距离dis1[i],每个点到b的最短距离dis2[i],每个点到c的最短距离dis3[i],

我们发现a->b->c要么通过一个中间点,要么是一条直线,而第二种情况即中间点为b,因为dis2[i]存在重复,

所以我们将权值最小的p[i]赋给b->i之间的路径,剩下的路径再依次从小到大赋值,然后我们枚举每个点i,找到最小值即可。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=2e5+5;
const ll INF=1e18+8;
ll p[MAXN],sum[MAXN];
struct node
{
    int to,nxt;
}e[MAXN<<1];
int head[MAXN],tot,n,m,a,b,c;
void add(int x,int y)
{
    e[tot].to=y;e[tot].nxt=head[x];head[x]=tot++;
}
void add_edge(int x,int y)
{
    add(x,y);add(y,x);
}
ll dis1[MAXN],dis2[MAXN],dis3[MAXN];
void bfs(int s,ll *dis)
{
    queue<int>q;
    q.push(s);dis[s]=0;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=head[u];~i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(!dis[v]&&v!=s)
            {
                dis[v]=dis[u]+1;q.push(v);
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);
    int t;cin>>t;
    while(t--)
    {
        memset(head,-1,sizeof(head));tot=0;
        for(int i=0;i<=n;i++)
            dis1[i]=0,dis2[i]=0,dis3[i]=0;
        cin>>n>>m>>a>>b>>c;
        for(int i=1;i<=m;i++)
        {
            cin>>p[i];
        }
        for(int i=1;i<=m;i++)
        {
            int x,y;cin>>x>>y;add_edge(x,y);
        }
        sort(p+1,p+1+m);
        for(int i=1;i<=m;i++)
        {
            sum[i]=sum[i-1]+p[i];
        }
        bfs(a,dis1);bfs(b,dis2);bfs(c,dis3);
        ll ans=INF;
        for(int i=1;i<=n;i++)
        {
            if(dis1[i]+dis3[i]+dis2[i]<=m)
            {
                ans=min(ans,sum[dis1[i]+dis3[i]+dis2[i]]+sum[dis2[i]]);
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ljxdtc666/p/12812488.html