1. 程式人生 > 其它 >洛谷P1352 - 沒有上司的舞會 - 樹形DP

洛谷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];//上司參加時,下屬不參加
		}
	}
}