zoukankan      html  css  js  c++  java
  • P2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gat…

    题目描述

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

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

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

    输入输出格式

    输入格式:

    第一行:一个整数 N 。

    第二到 N+1 行:第 i+1 行有一个整数 Ci

    第 N+2 行到 2*N 行:第 i+N+1 行为 3 个整数:Ai,Bi和 Li

    输出格式:

    第一行:一个值,表示最小的不方便值。

    输入输出样例

    输入样例#1: 
    5 
    1 
    1 
    0 
    0 
    2 
    1 3 1 
    2 3 2 
    3 4 3 
    4 5 3 
    
    输出样例#1: 
    15 

    代码

    本题有两种解决方法

    1.二次扫描,换根法

    先求出某一点不方便度,通过转移root

    那么f[to]=f[u]-s[to]*e[i].val+(sum-s[to])*e[i].val;

    其中f表示不方便度,s[to]表示子树牛数,sum-s[to]表示子树父节点的牛数

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=100000+100;
    int head[maxn];
    long long p[maxn],f[maxn],s[maxn];
    long long sum,ans;
    struct edge
    {
        int to,next;
        long long val;
    }e[maxn<<2];
    int size=0;
    inline long long read()
    {
        long long x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return x*f;
    }
    void addedge(int u,int v,long long w)
    {
        e[++size].to=v;e[size].val=w;e[size].next=head[u];head[u]=size;
    }
    void dfs1(int u,int fa)
    {
        for(int i=head[u];i;i=e[i].next)
        {
            int to=e[i].to;
            if(to==fa)continue;
            dfs1(to,u);
            f[u]+=f[to]+s[to]*e[i].val;
            s[u]+=s[to];
        }
        s[u]+=p[u];
    }
    void dfs2(int u,int fa)
    {
        for(int i=head[u];i;i=e[i].next)
        {
            int to=e[i].to;
            if(to==fa)continue;
            f[to]=f[u]-s[to]*e[i].val+(sum-s[to])*e[i].val;
            dfs2(to,u);
        }
    }
    int main()
    {
        int n=read();
        for(int i=1;i<=n;i++)
        s[i]=read(),sum+=s[i];
        for(int i=1;i<n;i++)
        {
            int u=read(),v=read();
            long long w=read();
            addedge(u,v,w);
            addedge(v,u,w);
        }
        dfs1(1,0);
        ans=f[1];
        dfs2(1,0);
        for(int i=1;i<=n;i++)
        ans=min(ans,f[i]);
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    2.树的重心

    定义

    树的重心:子树中最大的子树节点数最少的点,删去重心后,生成的多棵树尽可能平衡。

    树的重心具有一下性质

    1 :树中所有点到重心的距离和是最小的,一棵树最多有两个重心

     2 :把两棵树通过加一条边得到一颗新的树,新的树的重心必然在连接原来两棵树重心的路径上

     3 :一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置

    由性质1我们可以想到树的重心的解法,猜想该点,在树的重心上

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=100000+100;
    int head[maxn];
    long long p[maxn],d[maxn],ms[maxn],s[maxn];
    int g=1;
    long long sum,ans;
    struct edge
    {
        int to,next;
        long long val;
    }e[maxn<<2];
    int size=0;
    inline long long read()
    {
        long long x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return x*f;
    }
    void addedge(int u,int v,long long w)
    {
        e[++size].to=v;e[size].val=w;e[size].next=head[u];head[u]=size;
    }
    void dfs1(int u,int fa)
    {
        s[u]=p[u];
        for(int i=head[u];i;i=e[i].next)
        {
            int to=e[i].to;
            if(to==fa)continue;
            dfs1(to,u);
            s[u]+=s[to];
            ms[u]=max(ms[u],s[to]);
        }
        ms[u]=max(ms[u],sum-s[u]);
    }
    void dfs2(int u,int fa)
    {
        for(int i=head[u];i;i=e[i].next)
        {
            int to=e[i].to;
            if(to==fa)continue;
            d[to]=d[u]+e[i].val;
            ans+=d[to]*p[to];
            dfs2(to,u);
        }
    }
    int main()
    {
        int n=read();
        for(int i=1;i<=n;i++)
        p[i]=read(),sum+=p[i];
        for(int i=1;i<n;i++)
        {
            int u=read(),v=read();
            long long w=read();
            addedge(u,v,w);
            addedge(v,u,w);
        }
        dfs1(1,0);
        for(int i=2;i<=n;i++)
        if(ms[i]<ms[g])g=i;
        dfs2(g,0);
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

  • 相关阅读:
    __name__使用方法,模块查找顺序和模块的绝对导入
    模块
    ATM程序结构
    迭代器
    常用内置方法
    生成式,匿名函数及内置函数部分使用方法
    算法之二分法和三元表达式
    redis配置文件
    PythonStudy——shutil 模块
    PythonStudy——pickle 模块 (泡菜)
  • 原文地址:https://www.cnblogs.com/DriverBen/p/10926433.html
Copyright © 2011-2022 走看看