题解 P2986 [USACO10MAR]伟大的奶牛聚集
Posted yuanqiqhfz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 P2986 [USACO10MAR]伟大的奶牛聚集相关的知识,希望对你有一定的参考价值。
题解 P2986 [USACO10MAR]伟大的奶牛聚集
很好的一道树形dp的题目,我们观察每一个点i的答案,发现答案 f[i] 由两部分组成:
A1.i所有子树中的犇集中到i点
A2.除了i的子树中的所有犇集中到i的父亲节点,再走到i点
f[i] = A1 + A2
我们发现i的答案和i的孩子有关,也和i的父亲有关。一般这样的问题用两次dfs就可以解决。(由于选谁是根节点都无所谓,以下以1号节点为根)
第一次dfs我们求出每一个点的 f[i], 意思是以i为根节点的子树中的牛集中到i点的“不方便值”。显然我们只要统计i点子树中牛的数量 q[i] 然后递推就可以了。
第二次dfs我们要把 f[i] 变成所有牛(而不是子树中的牛)集中到i点的不方便值。设i的父亲是j,i到j的距离是s。ans[i] 就等于 f[j] + (q[1] - q[i]) * s - q[u] * s。 (多想几遍就想通了,要理解上面A1A2的意思)
下面放代码:
#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
以上是关于题解 P2986 [USACO10MAR]伟大的奶牛聚集的主要内容,如果未能解决你的问题,请参考以下文章
洛谷 P2986 [USACO10MAR]伟大的奶牛聚集(树形动规)
洛谷 P2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gat…
P2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gat…