标签:
回想一下 hiho 03 和 hiho 04 的 KMP 算法和 Trie 图。
Trie 图其实就是在树上做 KMP。
同样地,树上的动归其实就是……在树上做动归。
之前做的动归是在线性表上做的,只有一条路径,树上的动归有多条路径,但这本质上是没有区别的。
状态 f[i, j] 含义是以 i 为根的树包含根节点在内不超过 j 个节点的连通分量构成的最大和。
状态转移方程:f[i, j] = max(f[i, j], f[i, j – k] + f[i_child, k]),其中 i_child 表示 i 的子节点。
需要注意的是转移顺序,j 应该从大到小转移:当 i_child 确定,计算 f[i, j] 需要用到 f[i, j – k],此时的 f[i, j – k] 应当是没有使用 i_child 这棵子树上的节点的。
结果的状态表示是 f[1, m]。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> tree[105];
int f[105][105];
int n, m;
void dfs(int root_idx, int pa_idx) {
int len = tree[root_idx].size();
for (int i = 0; i < len; i++) {
int sub_idx = tree[root_idx][i];
if (sub_idx != pa_idx) {
dfs(sub_idx, root_idx);
for (int j = m; j > 1; j--) {
for (int k = 1; k < j; k++) {
f[root_idx][j] = max(f[root_idx][j], f[root_idx][j - k] + f[sub_idx][k]);
}
}
}
}
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> f[i][1];
}
for(int i = 1; i < n; i++) {
int a, b;
cin >> a >> b;
tree[a].push_back(b);
tree[b].push_back(a);
}
dfs(1, 0);
cout << f[1][m] << endl;
return 0;
}
标签:
原文地址:http://www.cnblogs.com/xblade/p/4478850.html