没有上司的舞会
Ural 大学有 N 名职员,编号为 1∼N。
他们的关系就像一棵以校长为根的树,父节点就是子节点的直接上司。
每个职员有一个快乐指数,用整数 HiHi 给出,其中 1≤i≤N。
现在要召开一场周年庆宴会,不过,没有职员愿意和直接上司一起参会。
在满足这个条件的前提下,主办方希望邀请一部分职员参会,使得所有参会职员的快乐指数总和最大,求这个最大值。
输入样例:
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
输出样例:
5
思路
一个人不能和直系上司参加聚会, 即选则根节点时不能再选择子节点
似乎跟 开餐馆 有点类似, 相邻的只能选其中一个。
不过数据结构从数组变成了图。
在数组中我们是遍历每一个点, 将所有能转移过来的状态转移一遍。
对于该题来说, 就是 该点选时, 从父节点之前的点转移过来, 该点不选时, 则从父节点转移 有条件的转移。
遍历用的是 图的深度有限遍历DFS, 也就是说从顶端节点开始, 一层层找到子节点之后释放并处理。
那么需要反过来考虑: 当前点选了之后, 由子节点的子节点转移 当前点不选, 由子节点转移
展开!
状态表示: f[i][0]
当前点不选的快乐指数总和, f[i][1]
当前点选的快乐指数总和
状态属性: max
状态计算: f[i][0] += max(f[j][1], f[j][0])
, f[i][1] += f[j][0]
, j 是该点的所有子节点
代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 6e3 + 10, M = 2 * N;
int h[N], e[N], ne[M], idx;
int happy[N], f[N][2];
bool has_father[N];
int n;
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u)
{
f[u][1] = happy[u];
for(int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
dfs(j);
f[u][1] += f[j][0];
f[u][0] += max(f[j][1], f[j][0]);
}
}
int main()
{
memset(h, -1, sizeof h);
cin >> n;
for(int i = 1; i <= n;i++) cin >> happy[i];
for(int i = 1; i < n; i++)
{
int a,b;
scanf("%d %d", &a, &b);
add(b,a);
has_father[a] = true;
}
// 找到根节点
int root = 1;
while(has_father[root]) root++;
dfs(root);
cout << max(f[root][0], f[root][1]) << endl;
return 0;
}