回想一下 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;
}
 
                    
                     
                    
                 
                    
                 
 posted on
 posted on 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号