1 条题解
-
0
题意分析:
乌拉尔国立大学举办80周年校庆派对,大学的管理结构是一个树状层级,以校长为根节点。派对的出席规则是:如果一个员工出席派对,那么他的直属上司不能出席。每位员工都有一个欢乐值(可能为负数),目标是选择一组员工出席派对,使得在满足上述规则的前提下,所有出席员工的欢乐值总和最大。
解题思路:
这个问题可以抽象为树形动态规划(Tree DP)的问题。我们需要在树的结构上进行动态规划,考虑每个节点(员工)是否被选中(出席派对)的情况,同时满足题目给出的约束条件。
动态规划状态定义
对于树中的每个节点u,我们可以定义两个状态: dp[u][0]:表示不选择节点u时,以u为根的子树中能获得的最大欢乐值总和。 dp[u][1]:表示选择节点u时,以u为根的子树中能获得的最大欢乐值总和。
状态转移
如果选择节点u(即u出席派对),那么u的所有子节点都不能被选择。因此: $dp[u][1] = happy[u] + sum(dp[v][0] for all children v of u)$
如果不选择节点u(即u不出席派对),那么u的子节点可以选择出席或不出席,我们选择对总和更有利的情况。因此: $dp[u][0] = sum(max(dp[v][0], dp[v][1]) for all children v of u)$
初始条件
对于叶子节点(没有子节点的节点): (不选叶子,子树和为0) (选叶子,子树和为叶子的欢乐值)
#include <iostream> #include <vector> #include <cstdio> using namespace std; const int MAXN = 6005; int n; int rating[MAXN]; vector<int> children[MAXN]; int dp[MAXN][2]; // dp[i][0]表示不选i时的最大欢乐值,dp[i][1]表示选i时的最大欢乐值 bool hasParent[MAXN]; void dfs(int u) { dp[u][0] = 0; dp[u][1] = rating[u]; for (int i = 0; i < children[u].size(); i++) { int v = children[u][i]; dfs(v); dp[u][0] += max(dp[v][0], dp[v][1]); dp[u][1] += dp[v][0]; } } int main() { while (scanf("%d", &n) == 1) { // 初始化 for (int i = 1; i <= n; i++) { children[i].clear(); hasParent[i] = false; } // 读入欢乐值 for (int i = 1; i <= n; i++) { scanf("%d", &rating[i]); } // 读入树结构 int L, K; while (scanf("%d %d", &L, &K) == 2) { if (L == 0 && K == 0) break; children[K].push_back(L); hasParent[L] = true; } // 找到根节点 int root = 1; while (root <= n && hasParent[root]) root++; // 动态规划计算 dfs(root); // 输出结果 printf("%d\n", max(dp[root][0], dp[root][1])); } return 0; }
- 1
信息
- ID
- 1343
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 13
- 已通过
- 1
- 上传者