题目描述
*某大学有 n 个职员,编号为 1…n。
他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 r [ i ] r[ i ] r[i],但是呢,如果某个职员的直接上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。
输入格式
输入的第一行是一个整数 n n n。
第 2 到第 ( n + 1 ) (n + 1) (n+1) 行,每行一个整数,第 ( i + 1 ) (i + 1) (i+1) 行的整数表示 ii 号职员的快乐指数 r [ i ] r[ i ] r[i] 。
第 ( n + 2 ) (n + 2) (n+2)到第 ( 2 n + 1 ) (2n+1) (2n+1) 行,每行输入一对整数 l , k l, k l,k,代表 k k k 是 l l l 的直接上司。
输出格式
输出一行一个整数代表最大的快乐指数。
样例输入
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
样例输出
5
说明/提示
数据规模与约定
对于 100% 的数据,保证
1
≤
n
≤
6
∗
10
³
1 ≤ n ≤ 6*10³
1≤n≤6∗10³,
−
128
≤
r
[
i
]
≤
127
-128 ≤ r[ i ] ≤ 127
−128≤r[i]≤127,
1
≤
l
,
k
≤
n
1 ≤ l,k ≤ n
1≤l,k≤n。
且给出的关系一定是一棵树。
一道入门级别的树形dp。
在攻克题目之前,我们先来分析一下树形dp的运作方式。
树形dp为了保证取点最优,必须从叶节点不断推向根节点(废话 ),求得最右值。众所周知,根节点是没有爸爸(上司)的,我们可以亲切地称呼他为孤儿(手动滑稽^ _ ^)
然后开始分析样例:(注:图1为编号关系,图2为快乐值)
是不是发现只有5没有直属上司(孤儿 )?这个(孤儿 ) 就是可爱的根节点,那我们该怎么寻找呢?
别急啊,我们先建树。
建树的方法主要有两种:
1.STL
v
e
c
t
o
r
vector
vector 建树
2.链式前向星建树
由于本博主更喜欢STL中的vector建树(说白了就是不咋会链式前向星 )
所以,关于vector的学习,你们可以去一位大犇的博客看看。
网址点我
首先,我们通过
v
e
c
t
o
r
vector
vector来定义
s
o
n
[
6005
]
son[6005]
son[6005],即
v
e
c
t
o
r
<
i
n
t
>
s
o
n
vector<int>son
vector<int>son
用
s
o
n
[
i
]
son[i]
son[i]来保存
i
i
i结点的所有儿子,建树。
定义root,运用root寻找根节点:
for (register int i = 1; i < n; i++) {
int k, l;
scanf ("%d%d", &k, &l);
son[l].push_back(k);//记录
v[k] = 1; //因为l是k的直属上司,所以k一定不是孤儿
}
int root = 0;
for (register int i = 1; i <= n; i++){//一起找孤儿
if (!v[i]){//如果没有被记录过,那么证明他是孤儿
root = i; //找孤儿的位置(根节点位置)
break;
}
}
定义二维数组
f
[
6005
]
[
2
]
f[6005][2]
f[6005][2],
以
f
[
i
]
[
0
]
f[i][0]
f[i][0]定义上司去,下属不去,
以
f
[
i
]
[
1
]
f[i][1]
f[i][1]定义上司不去,下属去。
则得出动态转移方程:(y是x的儿子)
上司去,下属不去:
f
[
x
]
[
0
]
+
=
m
a
x
(
f
[
y
]
[
0
]
,
f
[
y
]
[
1
]
)
f[x][0] += max(f[y][0],f[y][1])
f[x][0]+=max(f[y][0],f[y][1])
上司不去,下属去:
f
[
x
]
[
1
]
+
=
f
[
y
]
[
0
]
f[x][1] += f[y][0]
f[x][1]+=f[y][0]
f[x][0] += max (f[y][1], f[y][0]);//上司不去,下属去或不去
f[x][1] += f[y][0]; // 上司去,下属不去
分析结束上代码:
A
C
C
o
d
e
:
AC Code:
ACCode:
#include <bits/stdc++.h>
#define Max 6005
using namespace std;
int n, r[Max], v[Max], f[Max][2];
vector< int >son[Max];//STL
inline void dp (int x) {//dp
f[x][0] = 0;
f[x][1] = r[x];
for (register int i = 0; i < son[x].size(); i++) {
int y = son[x][i];
dp (y);//递归
f[x][0] += max (f[y][1], f[y][0]);//上司不去,下属去或不去
f[x][1] += f[y][0]; // 上司去,下属不去
}
return;
}
int main() {
memset(v, 0, sizeof(v));//记得清零(预处理)
scanf ("%d", &n);
for (register int i = 1; i <= n; i++)
scanf("%d", &r[i]);
for (register int i = 1; i < n; i++) {
int k, l;
scanf ("%d%d", &k, &l);
son[l].push_back(k);
v[k] = 1; //因为l是k的直属上司,所以k一定不是孤儿
}
int root = 0;
for (register int i = 1; i <= n; i++) {//一起找孤儿
if (!v[i]) {
root = i; //找孤儿
break;
}
}
dp (root);//dp
return !printf ("%d", max (f[root][1], f[root][0]));//省了一行
}
拜拜