Solution to a problem P2986 [USACO10MAR] great gathering cows

Solution to a problem P2986 [USACO10MAR] great gathering cows

Topic Link

A good tree dp topic, we observe answer every point i found the answer to f [i] consists of two parts:

A1.i all subtree Ben concentrated point i

A2. In addition to i sub-tree all ran to his father centralized node i, i then went to the point

f[i] = A1 + A2

We found that children of answers and i i is related to his father and i also relevant. Generally this problem can be solved with two dfs. (Since it does not matter finding out the root node, the root node to No. 1)

Dfs first time we find every point of f [i], i mean is for the sub-tree root node in the cattle concentrated to the point i "value is not convenient." Obviously we only statistical point i tree in the number of cattle q [i] then recursion on it.

We need a second dfs f [i] becomes all cows (instead of bovine subtree) concentrated convenient point i values. I that father j, i to j is the distance s. ans [i] equal to f [j] + (q [1] - q [i]) * s - q [u] * s. (Think figured out a few times to understand the meaning of the above A1A2)

Put the code below:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100005
#define ll long long
using namespace std;
inline int read()
{
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
    while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    return x * f;
}
ll ans = 1e15, f[N], c[N], q[N];
//f在两次dfs里含义不一样 c是每个点有多少牛 q是每个点和他的子树总共有多少牛
int tot, head[N], n;

struct edge
{
    int to, next, dis;
    edge() {}
    edge(int x, int y, int z) { to = x, next = y, dis = z; }
}a[2 * N];
//邻接表存图
void add(int from, int to, int dis)
{
    a[++tot] = edge(to, head[from], dis);
    head[from] = tot;
}

void dfs(int x, int fa)
{
    q[x] += c[x];
    for (int i = head[x]; i; i = a[i].next)
    {
        int u = a[i].to, s = a[i].dis;
        if (u != fa)
        {
            dfs(u, x);
            q[x] += q[u];
            f[x] += f[u] + q[u] * s;
        }
    }
}
//第一次dfs 求出A1
void dfs2(int x, int fa)
{
    for (int i = head[x]; i; i = a[i].next)
    {
        int u = a[i].to, s = a[i].dis;
        if (u != fa)
        {
            f[u] = f[x] + (q[1] - q[u]) * s - q[u] * s;
            dfs2(u, x);
        }
    }
}
//第二次dfs 求出每个点的答案
int main()
{
    n = read();
    for (int i = 1; i <= n; i++)
        c[i] = read();
    for (int i = 1; i < n; i++)
    {
        int a1 = read(), a2 = read(), a3 = read();
        add(a1, a2, a3);
        add(a2, a1, a3);
    }
    dfs(1, 1);
    dfs2(1, 1);
    for (int i = 1; i <= n; i++)
        ans = min(ans, f[i]); //在所有点中找到最方便的
    cout << ans << endl;
    return 0;
}

19.08.31

Guess you like

Origin www.cnblogs.com/YuanqiQHFZ/p/11622372.html