洛谷P2986 [USACO10MAR] Great Cow Gathering G(树形dp)
\(\Huge{洛谷P2986\ [USACO10MAR]\ Great\ Cow\ Gathering\ G}\)
本题有一道简单版本,难度属于树形dp的简单题。
题目地址:P3478 [POI2008] STA-Station - 洛谷
题解:[POI2008] STA-Station/洛谷P3478(树形dp)-CSDN博客
题意
有\(n\)个农场,每个农场相互可以到达(联通),有\(n-1\)条路连接这\(n\)个农场。每条路对应的有其长度\(L_i\),然后每个农场有若干头牛\(C_i\)。
现在要选择一个农场,并让所有牛都去,求再哪个农场举办能使得所有牛移动距离最小?输出最小的移动距离总和。
数据范围:
- \(1\leq n\leq 10^5\)
- \(1\leq A_i\leq B_i\leq n\)
- \(0 \leq C_i,L_i \leq 10^3\)。
思路
对于这道题,如果写过上面那道简单题的话,这道题很容易就能写出来。不过这一道也属于树形\(dp\)中的典中典。
这两道题都属于树形\(dp\)中的选择节点型。
对于这道题,假设x节点最优,那么x节点的最小移动距离总和=所有子节点的移动距离总和+每个子节点的子节点奶牛个数*这个子节点距离x的距离。
上面的描述可以用下列公式表示为:
\[b[x].second=\sum{b[i].second+b[i].first\times z}
\]
以上涉及到的每个节点的子孙节点个数以及移动距离总和,都可以通过一次\(dfs\)完成。
然后考虑从\(x\)节点转移到其子节点\(i\)的状态转移方程:
\[b[i].second = b[x].second + ((b[1].first - b[i].first) \times z) - b[i].first \times z
\]
第二个dfs中\(b[1].first\)相当于所有奶牛的个数。
标程
#define int long long
#define fi first
#define se second
const int N = 1e5 + 10;
int n, res;
vector<PII> a[N];
vector<PII> b(N);
void dfs1(int x, int y) {
for(auto [i, z] : a[x]) {
if(i == y) continue;
dfs1(i, x);
b[x].fi += b[i].fi;
b[x].se += b[i].fi * z + b[i].se;
}
}
void dfs2(int x, int y) {
for(auto [i, z] : a[x]) {
if(i == y) continue;
b[i].se = b[x].se + ((b[1].fi - b[i].fi) * z) - b[i].fi * z;
dfs2(i, x);
}
}
void Solved() {
cin >> n;
for(int i = 1; i <= n; i ++ ) {
cin >> b[i].fi;
}
for(int i = 1; i < n; i ++ ) {
int x, y, z; cin >> x >> y >> z;
a[x].push_back({y, z}); a[y].push_back({x, z});
}
dfs1(1, 1);
dfs2(1, 1);
res = 1e18;
for(int i = 1; i <= n; i ++ ) {
res = min(res, b[i].se);
}
cout << res << endl;
}

浙公网安备 33010602011771号