树形DP就是在树上的DP。(废话)
树形DP利用了一定的DP的思想。
给定一棵树,求这颗树每一个点的子树大小。 1 ≤ 点数 ≤ 1 0 6 1\le 点数\le 10^6 1≤点数≤106。
最基本的树形DP。
void dfs(int u, int fa)
{
sum[u] = 1;
for (auto &i : z[u])
{
if (i == fa)
continue ;
dfs(i, u);
sum[u] += sum[i];
}
}
定义
f
[
i
]
[
0
/
1
]
f[i][0/1]
f[i][0/1] 代表
i
i
i 为根的子树,没有选/选了。
然后进行树形DP。
f [ i ] [ 0 ] = ∑ j 是 i 的儿子 max ( f [ j ] [ 0 ] , f [ j ] [ 1 ] ) f[i][0] = \sum_{j是i的儿子} \max(f[j][0],f[j][1]) f[i][0]=j是i的儿子∑max(f[j][0],f[j][1])
f [ i ] [ 1 ] = ∑ j 是 i 的儿子 f [ j ] [ 0 ] f[i][1] = \sum_{j是i的儿子} f[j][0] f[i][1]=j是i的儿子∑f[j][0]
答案就是 max ( f [ i ] [ 0 ] , f [ i ] [ 1 ] ) , i ∈ [ 1 , n ] \max(f[i][0],f[i][1]),i\in [1,n] max(f[i][0],f[i][1]),i∈[1,n]。
#include
using namespace std;
const int N = 6010;
int f[N][2], v[N];
bool flag[N];
vector <int> z[N];
void dfs(int u, int fa = -1)
{
f[u][0] = 0, f[u][1] = v[u];
for (auto &i : z[u])
{
if (i == fa)
continue ;
dfs(i, u);
f[u][0] += max(f[i][0], f[i][1]);
f[u][1] += f[i][0];
}
}
signed main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i ++)
cin >> v[i];
for (int i = 1; i < n; i ++)
{
int a, b;
cin >> a >> b;
z[a].push_back(b);
z[b].push_back(a);
flag[a] = true;
}
int root = 1;
for (; root <= n; root ++)
if (!flag[root])
break;
dfs(root);
int mx = 0;
for (int i = 1; i <= n; i ++)
mx = max(mx, max(f[i][0], f[i][1]));
cout << mx << '\n';
return 0;
}