問題を解決P2986 [USACO10MAR]偉大な収集牛
良い木のDPトピック、私たちは私がFへの答えを見つけたすべてのポイントに答える観察[i]の2つの部分から成ります:
A1.iすべてのサブツリーベンは、私はポイントを集中しました
A2。Iサブツリーに加えて、すべてのiは、私は、ポイントに行った父の集中ノードに走りました
F [i]は= A1 + A2
私たちは、回答の子供たちと私は私が彼の父と私も関連するに関連していることがわかりました。一般的に、この問題は、二つのDFSで解決することができます。(それが1番にルートノード、ルートノードを見つける問題ではないので)
我々は、Fのすべてのポイントを見つけるDFS初めて[i]は、iが平均値iが点になるまで濃縮ウシのサブツリーのルートノードのためのものである「値は便利ではありません。」牛qの数は明らかに私たちだけの統計ポイント私の木、その上に[i]が、その後再帰。
[I](代わりにウシサブツリーの)すべての牛が便利点i値を濃縮なるfは、我々は、第二のDFSを必要とします。Iその父jを、私はjに距離sです。* S - Q [U] * S - F [J] +(Q [i]がQ [1])を[I]と等しくANS。(上記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