题意
N个人参加party, 每个人有一个愉快值,他们之间有上司和下属的关系, 当其上司参加,则下属就不能参加(不希望有上下属同时参加,这样会扫兴的),反之上司不参加,则下属可参加可不参加,他们之间的关系可以用一个树形结构来进行表示,现在需要从这里面选一些人去参加party,使得愉快值最大化.
也是醉了, 想明白了,方程就是写不出, 参考了人家的解题报告才弄出来…(⊙﹏⊙)b
思路
dp 问题. 其核心思想是将一个大的树,划分为一个个独立的小树, 而每一个小树的根节点又是其大一点树的叶子节点.
然后在小树中求得最优解,归并到大一点的树上去, 依次往上归, 从而求出其最优解.
dp[i][0]
表示i
不参加party的时候其获得的愉快值
dp[i][1]
表示i
参加partty的时候其获得的愉快值
Sample Input 的输入能画出如下图, 由于其是树形结构, 因此我们可以划分出多个小树,如图A
,B
,C
.
在树B(6->4, 7->4)
中,我们可以推导出:
- 当4
不参加party的时候, 那么6
和7
可去可不去,而我们需要的是愉快值的最大化,因此我们需要6
和7
去和不去的最大值.
方程式如下:
dp[4][0]+= max(dp[6][0],dp[6][1]+max(dp[7][0],dp[7][1]);
- 当4
参加party, 则6
和7
都不能参加.
方程式如下:
dp[4][1] += dp[6][0]+dp[6][0];
那么在树A
中,则同理可以推导出:
当5
参加会议时:
dp[5][1] += dp[4][0]+dp[3][0];
当5
不参加会议时:
dp[5][0]+= max(dp[4][0],dp[4][1]) + max(dp[3][0], dp[3][1]);
因此我们可以得出推导方程如下:
dp[i][1] += dp[j][0];
dp[i][0] += max(dp[j][0], dp[j][1]);
//poj - 2531
import java.util.Scanner;
public class Main {
// private static int[] happy = new int[6005];
private static int[] father = new int[6005];
private static int[][] dp = new int[6005][2];
private static boolean[] bl = new boolean[60005];
private static int N;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// while (scanner.hasNext()) {
N = scanner.nextInt();
for (int i = 1; i <= N; i++) {
dp[i][1] = scanner.nextInt();
}
int l;
int k;
while ((l = scanner.nextInt()) != 0 && (k = scanner.nextInt()) != 0) {
father[l] = k;
}
int root = 1;
while (father[root] != 0) {
root = father[root];
}
// System.out.println("root="+root);
dfs(root);
System.out.println(Math.max(dp[root][0], dp[root][1]));
}
private static void dfs(int node) {
bl[node] = true;
for (int i = 1; i <= N; i++) {
if (!bl[i] && father[i] == node) {
dfs(i); //递归下去求得dp[i][0]和dp[i][1]的值
dp[node][1] += dp[i][0];
dp[node][0] += Math.max(dp[i][0], dp[i][1]);
}
}
}
// }
}