洛谷P8127 [BalticOI 2021 Day2] The Xana coup 题解 树形DP
题目链接:https://www.luogu.com.cn/problem/P8127
题目大意:给定一棵包含
我的思路:
首先是树形DP,每个节点
上述所有状态(即
同时,这些操作都不考虑父节点的影响(因为我这里的状态都是根据子节点的状态推导当前节点的状态)。
除此之外,我用
然后就可以推导所有的状态了。
叶子节点
对于叶子节点
- 如果
a_u = 1 (也就是原始节点的权值为1 ),则: -
- 如果
a_u = 0 (也就是原始节点的权值为0 ),则: -
非叶子节点
对于当前节点
- 如果选择不操作,则它的子节点的状态必须都是
0 (设子节点为v ,则此时只跟f_{v,0} 、f_{v,2} 有关) - 如果选择操作,则它的子节点的状态必须都是
1 (设子节点为v ,则此时只跟f_{v,1} 、f_{v,3} 有关)
但是这里有一个需要思考的问题,就是:当前节点
影响主要在于 —— 子节点中操作过的点是奇数个还是偶数个。
所以可以额外定义四个状态:
首先:
-
g_{0,0} = h_{0,0} = 0 -
g_{0,1} = h_{0,1} = +\infty
其次,当
-
g_{i,0} = \min \{ g_{i-1,0} + f_{v,0}, g_{i-1,1} + f_{v,2} \} -
g_{i,1} = \min \{ g_{i-1,0} + f_{v,2}, g_{i-1,1} + f_{v,0} \} -
h_{i,0} = \min \{ h_{i-1,0} + f_{v,1}, h_{i-1,1} + f_{v,3} \} -
h_{i,1} = \min \{ h_{i-1,0} + f_{v,3}, h_{i-1,1} + f_{v,1} \}
当然我们需要的只有最终计算出来的
此时再分别讨论
当 a_u = 1 时:
当 a_u = 0 时:
示例程序:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
const int INF = (1<<29);
int n, a[maxn], f[maxn][4], g[maxn][2], h[maxn][2];
vector<int> e[maxn];
/**
f[u][0] 点权为 0,点未操作
f[u][1] 点权为 1,点未操作
f[u][2] 点权为 0,点有操作
f[u][3] 点权为 1,点有操作
*/
void dfs(int u, int p) {
int sz = e[u].size();
if (sz == 1 && u != 1) { // 叶子节点
if (a[u] == 1) {
f[u][0] = INF;
f[u][1] = 0;
f[u][2] = 1;
f[u][3] = INF;
}
else { // a[u] == 0
f[u][0] = 0;
f[u][1] = INF;
f[u][2] = INF;
f[u][3] = 1;
}
return;
}
vector<int> tmp;
for (auto v : e[u])
if (v != p)
dfs(v, u), tmp.push_back(v);
int m = tmp.size();
g[0][0] = h[0][0] = 0;
g[0][1] = h[0][1] = INF;
for (int i = 1; i <= m; i++) {
int v = tmp[i-1];
g[i][0] = min(INF, min(g[i-1][0] + f[v][0], g[i-1][1] + f[v][2]));
g[i][1] = min(INF, min(g[i-1][0] + f[v][2], g[i-1][1] + f[v][0]));
h[i][0] = min(INF, min(h[i-1][0] + f[v][1], h[i-1][1] + f[v][3]));
h[i][1] = min(INF, min(h[i-1][0] + f[v][3], h[i-1][1] + f[v][1]));
}
if (a[u] == 1) {
f[u][0] = g[m][1];
f[u][1] = g[m][0];
f[u][2] = min(INF, 1 + h[m][0]);
f[u][3] = min(INF, 1 + h[m][1]);
}
else {
f[u][0] = g[m][0];
f[u][1] = g[m][1];
f[u][2] = min(INF, 1 + h[m][1]);
f[u][3] = min(INF, 1 + h[m][0]);
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
e[u].push_back(v);
e[v].push_back(u);
}
for (int i = 1; i <= n; i++) scanf("%d", a+i);
dfs(1, -1);
int ans = min(f[1][0], f[1][2]);
if (ans == INF) puts("impossible");
else printf("%d\n", ans);
return 0;
}