yuwj  

树形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]));
又偷了懒没有写代码...
posted on 2025-04-15 22:48  xiaowang524  阅读(12)  评论(0)    收藏  举报