洛谷P1352 - 沒有上司的舞會 - 樹形DP
阿新 • • 發佈:2021-10-10
洛谷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];//上司參加時,下屬不參加 } } }