洛谷 P1352 没有上司的舞会(树形dp)
\(\Huge{洛谷 P1352 没有上司的舞会(树形dp)}\)
题目链接:P1352 没有上司的舞会 - 洛谷
题意
现有\(N\)名职员,编号为\(1∼N\),他们的关系就像一棵以校长为根的树,父节点就是子节点的直接上司。
每个职员有一个快乐指数\(H_i\),现在有一场宴会需要人来参加,但是没有职员愿意与其直接上司一起参加。参加的职员会获得快乐指数,现在希望获得的快乐指数最高。
思路
一道经典的树形dp问题,来自《算法竞赛进阶指南》。
跟据题意,我们可以发现:对于任意节点,都有选与不选两种状态,唯一的限制条件是其父节点。
因此我们可以出\(f[i][j]\),第一维表示以\(i\)作为根绝点时的最优解,第二维\(j\)有两种状态\(0,1\),分别表示职员\(i\)去或不去。
因此状态转移方程为:
- \(f(i,0) = \sum\max \{f(x,1),f(x,0)\}\)(上司不参加舞会时,下属可以参加,也可以不参加)
- \(f(i,1) = \sum{f(x,0)} + H_i\)(上司参加舞会时,下属都不会参加)
实现过程中我们可以以节点\(1\)为根节点然后dfs到最底层,然后逐层向上返回并判断。
标程
const int N = 6e3 + 10;
vector<int> a(N), b[N], f[N];
int res = 0;
void dfs(int x, int y) {
if(b[x].empty()) {
f[x][1] = a[x]; res = max(res, f[x][1]);
return;
}
int sum1 = 0, sum2 = 0, sum3 = 0;
for(auto i : b[x]) {
if(i == y) continue;
dfs(i, x);
//分别计算其子节点选或不选的和
sum1 += f[i][0]; sum2 += f[i][1];
sum3 += max(f[i][0], f[i][1]);
}
f[x][1] = sum1 + a[x];//当x选的时候,其子节点不能选
f[x][0] = sum3;//当x不选的时候,其子节点可选可不选
res = max(f[x][1], f[x][0]);//判断两种情况的最大值
}
void Solved() {
int n; cin >> n;
for(int i = 1; i <= n; i ++ ) cin >> a[i], f[i].resize(2);
for(int i = 1; i < n; i ++ ) {
int x, y; cin >> x >> y;
b[x].push_back(y); b[y].push_back(x);
}
dfs(1, 1);
cout << res << endl;
}

浙公网安备 33010602011771号