这题看着很花哨,实际很简单的,慢慢读题即可
题目:
Ural 大学有 N 名职员,编号为 1∼N
他们的关系就像一棵以校长为根的树,父节点就是子节点的直接上司
每个职员有一个快乐指数,用整数 Hi 给出,其中 1 ≤ i≤ N
现在要召开一场周年庆宴会,不过,没有职员愿意和直接上司一起参会
在满足这个条件的前提下,主办方希望邀请一部分职员参会,使得所有参会职员的快乐指数总和最大,求这个最大值
第一行一个整数 N
接下来 N 行,第 i 行表示 i 号职员的快乐指数 Hi
接下来 N−1 行,每行输入一对整数 L,K,表示 K 是 L 的直接上司
输出最大的快乐指数
1 ≤ N ≤ 6000
−128 ≤ Hi ≤ 127
输入:
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
输出:
5
public class 树形dp_没有上司的舞会 {
//树以邻接表的形式存储到h/ne/e
//由于题目中没有告诉我们根节点root是哪个点,那么只能用has_father记录一下所有有父节点的节点,那么false的就是root
//happy记录每个点的快乐值
//f表示状态,f[u][0]为以u为根节点,不选u节点的方案,f[u][1]为以u为根节点,选u节点的方案
public static int N = 6010, n, index = 0;
public static int[] h = new int[N], ne = new int[N], e = new int[N];
public static int[] happy = new int[N];
public static boolean[] has_father = new boolean[N];
public static int[][] f = new int[N][2];
public static void main(String[] args) {
//读入快乐值
Scanner in = new Scanner(System.in);
n = in.nextInt();
for (int i = 1; i<=n; i++) happy[i] = in.nextInt();
//读入所有点之间的连接,记得将头节点初始化为-1,要不然dfs会爆的哦~
Arrays.fill(h, -1);
for (int i = 0; i<n-1; i++) {
int a = in.nextInt(), b = in.nextInt();
insert(b, a);
has_father[a] = true;
}
//找到根节点root
int root = 1;
while (has_father[root]) root++; //如果has_father为false,说明就是根节点
dfs(root); //从根节点开始dfs更新状态
//最后选择选root还是不选root,即为答案
System.out.println(Math.max(f[root][0], f[root][1]));
}
//模拟在单链表头插入,相当于x单向连接y
public static void insert(int x, int y) {
e[index] = y;
ne[index] = h[x];
h[x] = index++;
}
//通过深搜dfs的形式更新状态
public static void dfs(int u) {
f[u][1] = happy[u]; //选择u,那么状态先加上u自己的快乐值
//很基础的邻接表遍历,遍历所有当前u点的子节点j,先将所有底部节点更新状态,再用子节点来更新u点(父节点)的状态
for (int i = h[u]; i!=-1; i = ne[i]) {
int j = e[i];
dfs(j);
//这里就是状态转移
f[u][0] += Math.max(f[j][0], f[j][1]);
f[u][1] += f[j][0];
}
}
}
思路:
终于有个相对简单的题了(哭),还是经典y式dp法
1.状态表示
f[u][0] :以u为根节点,不选u节点的方案
f[u][1] :以u为根节点,选u节点的方案
存储的值为Max,因为要找最大的快乐指数(快乐值)
2.状态计算
1.f[u][0], 不选u点
说明可以选择u点的子节点 j,或者不选u点的子节点 j,取这两种状态的max即可 (当然必须要计算所有u的子节点才可以)
也就是 f[u][0] += Max(f[j][0], f[j][1])
2.f[u][1], 选择u点
说明不能选u的子节点 j,因为下属不想和直系上司呆在一块
也就是只有一种情况:f[u][1] += f[j][0]
以题目为栗:
所有人的快乐值都是1,那么只也就是考虑如果能选到更多的子节点,自然就得到更多的快乐值
不选5的话,只能选3和4,快乐值就是1+1 = 2
选5的话,可以选5,1,2,6,7,快乐值就是1+1+1+1+1 = 5
(切记这题的重点就是,不能选已选点的子节点)
声明:
算法思路来源为y总,详细请见https://www.acwing.com/
本文仅用作学习记录和交流