E. Weights Distributing(图论)

E. Weights Distributing(图论,贪心)

题目传送门:

E. Weights Distributing

题目大意:

有n个点,m条路径,每次经过一条路径时都需要一次该路径的花费。有一个花费数组对应着每一条路径,要求给出一个权值分配方案使得从点a->b->c的花费最小为多少。

思路:

1.假设a->b之后b->c没有经过之前经过的点,那么也就是三点之间经过的路径是一条直线。
2.否则b->c经过了之前经过的x,那么也就有了a->x->b->x->c的路径。
那么b->x这一段路径经过了两次,所以我们优先给这一段路径分配权值,然后再为另外两段路径分配权值。

先求出a,b,c三点到其他点的最短距离,然后将花费数组贪心之后用前缀和优化一下即可。

AC Code

#include
using namespace std;
typedef long long LL;
const int N=2e5+10;
int dis[4][N];//a,b,c三个点到每个点的距离
LL sum[N],price[N];
vector<int>g[N];
struct node
{
     
    int to,dist;
};
priority_queue<node>que;
bool operator<(const node &p,const node &q)
{
     
    return p.dist>q.dist;
}
void dijkstra(int idx,int num)
{
     
    dis[idx][num]=0;
    que.push({
     num,0});
    while(!que.empty())
    {
     
        node now=que.top();
        que.pop();
        if(now.dist!=dis[idx][now.to]) continue;
        for(int i=0;i<g[now.to].size();i++)
        {
     
            int to=g[now.to][i];
            if(dis[idx][to]>dis[idx][now.to]+1)
            {
     
                dis[idx][to]=dis[idx][now.to]+1;
                que.push({
     to,dis[idx][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",&price[i]);
        sort(price+1,price+1+m);
        sum[0]=0;
        for(int i=1;i<=m;i++) sum[i]=sum[i-1]+price[i];
        for(int i=1;i<=3;i++)   //初始化    
            for(int j=1;j<=n;j++) 
                dis[i][j]=1e9;
        for(int i=1;i<=n;i++) g[i].clear();
        for(int i=1;i<=m;i++)
        {
     
            int u,v;
            scanf("%d%d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        dijkstra(1,a);
        dijkstra(2,b);
        dijkstra(3,c);
        LL res=1e18;
        for(int i=1;i<=n;i++)   //枚举每个中间点
        {
     
            int f=dis[1][i]+dis[2][i]+dis[3][i];
            if(f>m) continue;
            res=min(res,sum[f]+sum[dis[2][i]]);
        }
        printf("%lld\n",res);
    }
    //system("pause");
    return 0;
}

你可能感兴趣的:(图论,Codeforces,图论,思维,codeforces)