zoukankan      html  css  js  c++  java
  • [USACO10MAR]伟大的奶牛聚集

    [USACO10MAR]伟大的奶牛聚集

    Bessie正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会。当然,她会选择最方便的地点来举办这次集会。

    每个奶牛居住在 N(1<=N<=100,000) 个农场中的一个,这些农场由N-1条道路连接,并且从任意一个农场都能够到达另外一个农场。道路i连接农场A_i和B_i(1 <= A_i <=N; 1 <= B_i <= N),长度为L_i(1 <= L_i <= 1,000)。集会可以在N个农场中的任意一个举行。另外,每个牛棚中居住者C_i(0 <= C_i <= 1,000)只奶牛。

    在选择集会的地点的时候,Bessie希望最大化方便的程度(也就是最小化不方便程度)。比如选择第X个农场作为集会地点,它的不方便程度是其它牛棚中每只奶牛去参加集会所走的路程之和,(比如,农场i到达农场X的距离是20,那么总路程就是C_i*20)。帮助Bessie找出最方便的地点来举行大集会。                                   ——by洛谷(感谢洛谷少有的良心翻译)

    http://daniu.luogu.org/problem/show?pid=2986



    建图,然后把她当做以任意点为根的树,然后很容易想用树DP。我们发现a与其父节点b;a为集合点的路径有两类:

    1. 直接到a;(我们把到a路径符合此类的点集记为A);
    2. 先到b;(我们把到a路径符合此类的点集记为B);

    于是当我们知道f[b]时,f[a]即为在f[b]的基础上A中点不必走a->b,B中点要再走b->a,而A即是a的子树点集;

    得方程:

    f[a]=f[fa[a]]-tree[a]*dis(a->b)+(tree[root]-tree[a])*dis(a->b);

    (想象所有点先聚集于b,再全走到a,其中a的子树上节点多走了,故减去)

    代码如下:

    #include<cstdio>
    using namespace std;
    int n;
    int c[100001];
    long long f1[100001],f[100001];
    struct ss
    {
        int next,to,dis;
    }x[200000];
    int first[100001],num;
    long long all;
    void build(int f,int t,int d)
    {
        x[++num].next=first[f];
        x[num].to=t;
        x[num].dis=d;
        first[f]=num;
    }
    long long dfs(int ,int );
    void dp(int ,int ,int );
    
    int main()
    {
        scanf("%d",&n);
        int i,j,k,l;
        for(i=1;i<=n;i++)
            scanf("%d",&c[i]),all+=c[i];
        for(i=1;i<=n-1;i++)
        {
            scanf("%d%d%d",&j,&k,&l);
            build(j,k,l);
            build(k,j,l);
        }
        f[0]=dfs(1,-1);
        dp(1,0,0);
        all=100000000000000000;
        for(i=1;i<=n;i++)
        if(f[i]<all)
            all=f[i];
        printf("%lld",all);
        return 0;
    }
    
    long long dfs(int fa,int last)
    {
        int j;
        long long sum=0;
        j=first[fa];
        f1[fa]=c[fa];
        while(j)
        {
            if(x[j].to!=last)
            {
                sum+=dfs(x[j].to,fa)+x[j].dis*f1[x[j].to];
                f1[fa]+=f1[x[j].to];
            }
            j=x[j].next;
        }
        return sum;
    }
    void dp(int fa,int last,int di)
    {
        int j;
        f[fa]=f[last]-f1[fa]*di+(all-f1[fa])*di;
        j=first[fa];
        while(j)
        {
            if(x[j].to!=last)
                dp(x[j].to,fa,x[j].dis);
            j=x[j].next;
        }
    }

    祝AC哟;

    Just close your eyes, you`ll be alright, no one can hurt you after you die.
  • 相关阅读:
    《构建之法》4、17章精读
    2016012005+小学四则运算练习软件项目报告
    Week2-作业一——《构建之法》三章精读之想
    虚拟到现实
    脚踏实地,莫问前程
    2016012010 赵瑞雪 散列函数的应用及其安全性
    结对项目报告
    《构建之法》第四章、第十七章读书笔记
    2016012010+小学四则运算练习软件项目报告
    《构建之法》第一、二、十六章读书笔记
  • 原文地址:https://www.cnblogs.com/nietzsche-oier/p/6166142.html
Copyright © 2011-2022 走看看