版权声明:点个关注(^-^)V https://blog.csdn.net/weixin_41793113/article/details/88431075
问题描述
将举行一个庆祝乌拉尔国立大学80周年庆典的派对。大学有员工的等级结构。这意味着主管关系形成了一个植根于VE Tretyakov校长的树。为了使每个人都很有趣,校长不希望雇员和他或她的直接主管在场。人事办公室已评估每位员工的欢乐程度,因此每个人都有一些(评级)附加给他或她。您的任务是列出具有最大可能客人欢乐等级的客人名单。
输入
员工编号从1到N.第一行输入包含编号N. 1 <= N <= 6 000.后续N行中的每一行都包含相应员工的欢乐评级。Conviviality rating是一个整数,范围从-128到127.然后转到描述主管关系树的T行。树规范的每一行都有以下形式:
LK
这意味着第K名员工是第L名员工的直接主管。输入以
0 0 行结束
输出
输出应包含客人评级的最大总和。
样本输入
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0
样本输出
5
树形dp,可能是涉及到图论和dfs
目前总结如下:
1.“树”,当作有向图(而且还无环的)来处理,建图(树)的时候更为简单,只要在它和它的孩子节点之间加一条指向孩子的有向边就可以了。
2.dp还是一样的dp,但是树形dp往往不是“线性、水平”的了,而是要从叶子节点推到根节点(或者反过来),关系盘结的更为复杂。
这题是一道最简单的树形dp;方程也很容易想到
- 当i来的时候,dp[i][1] += dp[j][0];//j为i的下属
- 当i不来的时候,dp[i][0] +=max(dp[j][1],dp[j][0]);//j为i的下属
邻接表用动态数组存,因为是有向图,所以要找到总根,即最大的主管,然后再从根开始建树,维护dp
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
//dp[i][1]表示第i个参与者参加了,dp[i][0]表示第i个参与者没有参加
//状态转移方程就:
//dp[i][1]=dp[i][1]+dp[i-1][0]
//dp[i][0]=dp[i][0]+Max(dp[i-1][0],dp[i-1][1])
public class hdu1520 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while(in.hasNext()) {
n = in.nextInt();
dp = new int[n+1][2];
g = new ArrayList[n+1];
f = new int[n+1];
for(int i=1;i<=n;i++)
g[i] = new ArrayList<>();
for(int i=1;i<=n;i++) {
dp[i][1] = in.nextInt();
f[i] = -1;
}
while(true){
int a = in.nextInt();
int b = in.nextInt();
if(a==0 && b==0)
break;
g[b].add(a);
f[a] = b;//找根
}
int root = 1;
while(f[root]!=-1)
root = f[root];
dfs(root);
System.out.println(Math.max(dp[root][0], dp[root][1]));
}
}
static int n;
static List<Integer>[] g;
static int[][] dp;
static int[] f;
static void dfs(int u) {//熟练后的root,我会写成u
for(int i=0;i<g[u].size();i++) {
int v = g[u].get(i);
dfs(v);
dp[u][0] += Math.max(dp[v][0], dp[v][1]);
dp[u][1] += dp[v][0];
}
}
}