树形DP,状态定义版本,
和杭电上一场那个一类,也是操作定义状态,但是很磨人
杭电春季6 1004
https://acm.hdu.edu.cn/contest/problem?cid=1155&pid=1004
这种题目大体思路:(定义状态,分类讨论)
树形dp,定义转移思路:
分类讨论当前结点操作还是不操作,会是什么样的结果,处于什么状态?
牛客F:
每次操作只考虑将该节点和父亲节点,这样就不用考虑是哪个儿子被被染色
三种状态,
dp[u][0]:操作当前节点,父亲和u均被染色
dp[u][1]:当前节点不操作,儿子节点操作,使得当前节点被染色
dp[u][2]:当前节点不操作,所有儿子都被染色,被儿子的儿子操作
转移:
当前节点染色,儿子节点任意
dp[u][0] += min(dp[i][1], dp[i][2])
dp[u][1] += min(dp[i][1],dp[i][2])
当前节点不操作,由儿子染色,要看是哪个儿子来的,花费最少
dp[u][2] += dp[i][1]
当前节点不操作,儿子节点由孙子节点操作染色
代码
点击查看代码
int N;
cin >> N;
auto g = readGraph(N, N - 1);
vvll dp(N, {INT_MAX, 0, 0});
function<void(int, int)> dfs = [&](int u, int p) {
ll sum0 = 0, sum1 = 0, sum2 = 0, mn = INT_MAX, cnt = 0;
for (auto v: g[u]) {
if (v == p) continue;
dfs(v, u);
sum0 += dp[v][0];
sum1 += min(dp[v][0], dp[v][2]);
chmin(mn, dp[v][1] - min(dp[v][0], dp[v][2]));
cnt++;
}
if (cnt > 0) dp[u][0] = sum1 + mn + 1;
dp[u][1] = sum1;
dp[u][2] = sum0;
};
dfs(0, -1);
printf("%lld\n", min(dp[0][0], dp[0][2]));

浙公网安备 33010602011771号