洛谷

洛谷题单指南-树与图上的动态规划-P1352 没有上司的舞会

原题链接:https://www.luogu.com.cn/problem/P1352

题意解读:在一棵树中选择一些点,使得拥有最大的权值和,限制条件是选择一个点时不能选择其父节点。

解题思路:

如果由于所选择节点的最大权值和是一个状态,而这个状态可以由所有子树的状态推导出来,因此可以从树形DP的角度来思考该问题。

对于以u为根节点的树,u本身选与不选也是一种状态,将影响子树的选择。

1、状态表示

设f[u][0]表示u的子树中不选u的最大权值和,f[u][1]表示u的子树中选u的最大权值和

2、状态转移

对于u的所有子节点v,

不选u时,子节点v可以选或不选,所以有f[u][0] += max(f[v][0], f[v][1])
选u时,子节点只能不选,所以有f[u][1] += f[v][0]
3、初始化

f[u][0] = 0

f[u][1] = w[u]

4、结果

max(f[root][0], f[root][1])

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 6005;
int f[N][2]; // f[u][0]表示u的子树中不选u的最大权值,f[u][1]表示u的子树中选u的最大权值
vector<int> g[N];
int n;
int w[N]; //快乐指数
bool fa[N]; //标记是否有父节点

void dfs(int u, int fa)
{
    f[u][0] = 0; //不选u的最大快乐指数
    f[u][1] = w[u]; //选u的最大快乐指数

    for(int v : g[u])
    {
        if(v == fa) continue; //避免回到父节点
        dfs(v, u); //递归处理子节点

        f[u][0] += max(f[v][0], f[v][1]); //不选u时,子节点可以选或不选
        f[u][1] += f[v][0]; //选u时,子节点只能不选
    }
}

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        cin >> w[i];
    }
    for(int i = 1; i < n; i++)
    {
        int u, v;
        cin >> u >> v;
        g[v].push_back(u);
        fa[u] = true; //标记u有父节点
    }

    int root = 0;
    for(int i = 1; i <= n; i++)
    {
        if(!fa[i]) //找到没有父节点的节点,即根节点
        {
            root = i;
            break;
        }
    }

    dfs(root, 0);
    cout << max(f[root][0], f[root][1]); //输出根节点的最大快乐指数
    return 0;
}