洛谷P1352 - 没有上司的舞会 - 树形DP
洛谷P1352 - 没有上司的舞会
题目描述
某大学有 n 个职员,编号为 1…n。
他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。
现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 ri,但是呢,如果某个职员的直接上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。
所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。
输入格式
输入的第一行是一个整数 nn。
第 2 到第 (n+1) 行,每行一个整数,第 (i+1) 行的整数表示 i 号职员的快乐指数 ri。
第 (n+2) 到第 2n 行,每行输入一对整数 l,k,代表 k 是 l 的直接上司。
输出格式
输出一行一个整数代表最大的快乐指数。
思路分析:
树形DP问题,定义dp[x][1/0]表示节点x为根的节点,参加(1)/不参加(0)舞会时的最大快乐值。
初始状态 dp[x][1] = r[i]; //r[i]表示 i 号职员的快乐指数
dp[x][1]表示x参加,那么他的子节点就不参加,则他要加上所有子节点不参加时的快乐值,
即:dp[x][1] += dp[son][0];
dp[x][0]表示x不参加,那么他的子节点可能参加,也可能不参加,则他要加上所有子节点参加与不参加的最大快乐值,
即:dp[x][0] += Max(dp[son][0], dp[son][1]);
最后输出Max(dp[root][0], dp[root][1])
package dp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
/**
*
* 思路分析:
* 树形DP问题,定义dp[x][1/0]表示节点x为根的节点,参加(1)/不参加(0)舞会时的最大快乐值。
* 初始状态 dp[x][1] = r[i]; //r[i]表示 i 号职员的快乐指数
* dp[x][1]表示x参加,那么他的子节点就不参加,则他要加上所有子节点不参加时的快乐值,
* 即:dp[x][1] += dp[son][0];
* dp[x][0]表示x不参加,那么他的子节点可能参加,也可能不参加,则他要加上所有子节点参加与不参加的最大快乐值,
* 即:dp[x][0] += Max(dp[son][0], dp[son][1]);
* 最后输出Max(dp[root][0], dp[root][1])
*
* @author XA-GDD
*
*/
public class P1352_ThePartyWithoutTheBoss {
static int N;
static int [] r = new int[6001]; //职员的快乐指数
static ArrayList<ArrayList<Integer>> subor = new ArrayList<ArrayList<Integer>>(); //上司的直接下属
static ArrayList<ArrayList<Integer>> boss = new ArrayList<ArrayList<Integer>>(); //下属的直接上司
static int [][] dp = new int[6001][2]; //最大快乐指数和
static int ans;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
for(int i=1;i<=N;i++) {
st = new StringTokenizer(br.readLine());
r[i] = Integer.parseInt(st.nextToken());
}
for(int i=0;i<=N;i++) {
subor.add(new ArrayList<Integer>());
boss.add(new ArrayList<Integer>());
}
for(int i=0;i<N-1;i++) {
st = new StringTokenizer(br.readLine());
int l = Integer.parseInt(st.nextToken()); //子
int k = Integer.parseInt(st.nextToken()); //父
subor.get(k).add(l); //父对应的子节点,DFS时,找子节点
boss.get(l).add(k); //子对应的父节点,用于找根节点
}
int root = 0;
for(int i=1;i<=N;i++) {
if(boss.get(i).size()==0) { //没有父节点时,即为根节点
root = i;
}
}
dfs(root);
ans = Math.max(dp[root][0], dp[root][1]);
System.out.println(ans);
}
static void dfs(int x) {
dp[x][1] = r[x];
for(int i=0;i<subor.get(x).size();i++) {
int sub = subor.get(x).get(i);
dfs(sub);
dp[x][0] += Math.max(dp[sub][0], dp[sub][1]); //上司不参加时,取下属参加和不参加的最大值
dp[x][1] += dp[sub][0];//上司参加时,下属不参加
}
}
}
浙公网安备 33010602011771号