题目

July 8, 2021 · View on GitHub

一颗树有 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

参考答案

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace  std;

const int N = 1010;

int n, root;
struct Node
{
    int p, s, v;
    double avg;
}nodes[N];

int find()
{
    double avg = 0;
    int res = -1;
    for (int i = 1; i <= n; i ++ )
        if (i != root && nodes[i].avg > avg)
        {
            avg = nodes[i].avg;
            res = i;
        }
    return res;
}

int main()
{
    cin >> n >> root;
    int ans = 0;
    for (int i = 1; i <= n; i ++ )
    {
        cin >> nodes[i].v;
        nodes[i].avg = nodes[i].v;
        nodes[i].s = 1;
        ans += nodes[i].v;
    }
    for (int i = 0; i < n - 1; i ++ )
    {
        int a, b;
        cin >> a >> b;
        nodes[b].p = a;
    }

    for (int i = 0; i < n - 1; i ++ )
    {
        int p = find();
        int father = nodes[p].p;
        ans += nodes[p].v * nodes[father].s;
        nodes[p].avg = -1;
        for (int j = 1; j <= n; j ++ )
            if (nodes[j].p == p)
                nodes[j].p = father;
        nodes[father].v += nodes[p].v;
        nodes[father].s += nodes[p].s;
        nodes[father].avg = (double)nodes[father].v / nodes[father].s;
    }

    cout << ans << endl;
    return 0;
}