标签:
回想一下 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