洛谷P1352 - 没有上司的舞会 - 树形DP

洛谷P1352 -  没有上司的舞会

题目描述

某大学有 n 个职员,编号为 1n。

他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。

现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 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];//上司参加时,下属不参加
		}
	}
}

  

posted @ 2021-10-10 10:08  晓暮云  阅读(222)  评论(0)    收藏  举报