zoukankan      html  css  js  c++  java
  • Acwing 115 给树染色 (贪心)

    题面

    一颗树有 n 个节点,这些节点被标号为:1,2,3…n,每个节点 i 都有一个权值 A[i]。

    现在要把这棵树的节点全部染色,染色的规则是:

    根节点R可以随时被染色;对于其他节点,在被染色之前它的父亲节点必须已经染上了色。

    每次染色的代价为T*A[i],其中T代表当前是第几次染色。

    求把这棵树染色的最小总代价。

    输入格式
    第一行包含两个整数 n 和 R ,分别代表树的节点数以及根节点的序号。

    第二行包含 n 个整数,代表所有节点的权值,第 i 个数即为第 i 个节点的权值 A[i]。

    接下来n-1行,每行包含两个整数 a 和 b ,代表两个节点的序号,两节点满足关系: a 节点是 b 节点的父节点。

    除根节点外的其他 n-1 个节点的父节点和它们本身会在这 n-1 行中表示出来。

    同一行内的数用空格隔开。

    输出格式
    输出一个整数,代表把这棵树染色的最小总代价。

    数据范围
    1≤n≤1000,
    1≤A[i]≤1000
    输入样例:
    5 1
    1 2 1 2 4
    1 2
    1 3
    2 4
    3 5
    输出样例:
    33

    思路

    太难....是这样的,我们首先考虑没有树形结构的情况,我们应该如何染色,对的,我们当然想到排序不等式,先染权值大的。那么加了树的结构限制说明了什么,说明了我们在给一个点染色之前,我们必须先给它的父亲染色,所以当我们沿着原来的思路去想的时候,就会发现,如果这个时候我们想要染一个权值最大的点,就必须先去满足他的父亲。那么我们其实可以把a和b看成一个节点一起染色,那么问题最后一定会变成,这一对点和另外一个点的大小关系,当我们考虑两种情况并且做差比较的时候可以发现,如果我们要先染点对,那么符合的条件是c小于点对的均值,拓展到点对和点对直接也是一样。基于这样的思路,我们每次找出点的平均值最大的点,把他并入父亲,更新ans并且同时打上lazy tag,最后在n-1次的更新后,得到最后的ans。

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<vector>
    using namespace std;
    const int maxn=1010;
    int n,root;
    struct node {
        int father,sum;
        int size;
        double avg;
    }a[maxn];
    inline int find () {
        double avg=0;
        int ans=-1;
        for (int i=1;i<=n;i++) {
            if (a[i].avg>avg&&i!=root) {
                ans=i;
                avg=a[i].avg;
            }
        }
        return ans;
    }
    int main () {
       int ans=0;
       cin>>n>>root;
       for (int i=1;i<=n;i++) {
           node &nd=a[i];
           nd.size=1;
           cin>>nd.sum;
           nd.avg=nd.sum;
           ans+=nd.sum;
       }
       for (int i=1;i<=n;i++) {
           int x,y;
           cin>>x>>y;
           a[y].father=x;
       }
       for (int i=0;i<n-1;i++) {
           int ver=find ();
           int f=a[ver].father;
           ans+=a[ver].sum*a[f].size;
           a[ver].avg=-1;
           for (int j=1;j<=n;j++) {
               if (a[j].father==ver) a[j].father=f;
           }
           a[f].size+=a[ver].size;
           a[f].sum+=a[ver].sum;
           a[f].avg= (double ) a[f].sum/a[f].size;
       }
       cout<<ans<<endl;
        return 0;
    }
    
  • 相关阅读:
    前端知识---html
    Python3中的运算符
    Python中的print、input函数以及Python中交换两个变量解析
    我的第一个Python程序,定义主函数,eval、format函数详解,
    MySQL创建索引
    认识MySQL中的索引
    MySQL中的函数
    MySQL的查询语句
    MySQL中增删改操作
    MySQL中的运算符和时间运算
  • 原文地址:https://www.cnblogs.com/hhlya/p/13332626.html
Copyright © 2011-2022 走看看