计数类$DP$:整数划分
//计数 DP:整数划分(完全背包问题思路)
int IntegerPartitioning(int n, int M){
int DP[n + 1];
DP[0] = 1;
for(int i = 1; i <= n; i++){
for(int j = i; j <= n; j++){
//前 i-1 个数组成 j 的方法加上前 i 个数组成 j-i 的方法
DP[j] = (DP[j] + DP[j - i]) % M;
}
}
return DP[n];
}
//计数 DP:整数划分
int IntegerPartitioning(int n, int M){
int DP[n + 1][n + 1];
DP[0][0] = 1;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= i; j++){
//j 个数可以表达成和为 i 的方案数
//转移方程是最小值不为 1 的方案加上最小值为 1 的方案
DP[i][j] = (DP[i - 1][j - 1] + DP[i - j][j]) % M;
}
}
int res = 0;
for(int i = 1; i <= n; i++){
res = (res + DP[n][i]) % M;
}
return res;
}
数位统计$DP$:计数问题
int get(int n){
int res = 0;
while(n){
res++;
n /= 10;
}
return res;
}
//求出数 x 在 0~n 中出现的次数
int count(int n, int x){
int res = 0, dgt = get(n);
// 循环每一位,累加数 x 在每一位上出现的次数
for(int i = 1; i <= dgt; i++ ) {
int p = pow(10, dgt - i);
// l 代表当前枚举到的位左边的数
int l = n / p / 10;
// r 代表当前枚举到的位右边的数
int r = n % p;
// dj 代表当前枚举到的位上的数
int dj = n / p % 10;
if(x != 0){
res += l * p;
}else{
res += (l - 1) * p;
}
if(x == dj){
res += r + 1;
}
if(x < dj){
res += p;
}
}
return res;
}
void CountingProblem(int a, int b){
if(a > b){
swap(a, b);
}
for(int i = 0; i <= 9; i++ ){
cout << count(b, i) - count(a - 1, i) << ' ';
}
}
树形$DP$:没有上司的舞会
//树形 DP:没有上司的舞会
#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
#define mem(vis, num) memset(vis, num, sizeof(vis))
using namespace std;
const int N = 6010;
int n;
int happy[N];
int h[N], e[N], ne[N], idx;
int DP[N][2];
bool has_father[N];
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u){
DP[u][1] = happy[u];
for(int i = h[u]; i != -1; i = ne[i]){
int j = e[i];
dfs(j);
DP[u][0] += max(DP[j][0], DP[j][1]);
DP[u][1] += DP[j][0];
}
}
//f[u,0]表示所有从以 u 为根的子树中选择,并且不选择 u 这个点的方案
//f[u,1]表示所有从以 u 为根的子树中选择,并且选择 u 这个点的方案
int main(){
cin >> n;
for(int i = 1; i <= n; i++ ){
cin >> happy[i];
}
mem(h, -1);
for (int i = 0; i < n - 1; i ++ ) {
int a, b;
cin >> a >> b;
has_father[a] = true;
add(b, a);
}
int root = 1;
while(has_father[root]){
root++;
}
dfs(root);
cout << max(DP[root][0], DP[root][1]) << endl;
return 0;
}



