JZOJ_7.7C组第四题 景点中心

题意

给出几个点,每个点上有一些人,两个点之间有一条路径,我们要找到一个点使得所有人走到这个点的路径总和最短。

思路

枚举。把这个图看成一个树,我们把每个点和它子节点的人数总和求出来,还有每个点的子节点走到这个点上的路径总和求出来。然后用dfs枚举每一个点作为根节点时的路径总和的最小值并记录下节点就好了。

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 1000001
using namespace std;
struct node{
    int next,to,w;
}e[N];
int head[N],tot,n,x,y,w,v[N];
long long c[N],f[N],peo[N],ans,num[N];
void add(int x,int y,int w) {e[++tot].to=y;e[tot].w=w;e[tot].next=head[x];head[x]=tot;}
void dp1(int x,int dep)
{
    v[x]=true;
    peo[x]=num[x];//peo[i]是第i个点的子节点和自己的人数总和 
    f[x]=num[x]*dep;//f[i]表示所有点上的人走到点f的路径总和 
    for (int i=head[x];i;i=e[i].next)
    {
        int y=e[i].to;
        if (!v[y])
        {
            dp1(y,dep+e[i].w);
            f[x]+=f[y];
            peo[x]+=peo[y];
        }
    }
}
void dp2(int x,int last,int from)//from上一条边 
{
    v[x]=1;
    if (x!=1) c[x]=c[last]+(peo[1]-peo[x])*e[from].w-peo[x]*e[from].w;//我们如果设x为集中点,那它的子节点和自己少走了peo[x]*e[from].w,其他的点多走了(peo[1]-peo[x])*e[from].w。
    if (c[x]<c[ans]) ans=x;//更新答案
    for (int i=head[x];i;i=e[i].next)
    {
        y=e[i].to;
        if (!v[y]) dp2(y,x,i);
    }
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%lld",&num[i]);
    for (int i=1;i<n;i++)
    {
        scanf("%d%d%d",&x,&y,&w);
        add(x,y,w);
        add(y,x,w);
    }
    c[0]=1e18;//初始化答案为很大的值
    dp1(1,0);//求人数和路径
    memset(v,0,sizeof(v));
    c[1]=f[1];
    dp2(1,0,0);//求最后答案
    printf("%lld\n%lld",ans,c[ans]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值