刷油漆(hihocoder1055)树形DP
时间限制:10000ms
描述
上回说到,小Ho有着一棵灰常好玩的树玩具!这棵树玩具是由N个小球和N-1根木棍拼凑而成,这N个小球都被小Ho标上了不同的数字,并且这些数字都是处于1..N的范围之内,每根木棍都连接着两个不同的小球,并且保证任意两个小球间都不存在两条不同的路径可以互相到达。没错,这次说的还是这棵树玩具的故事!
小Ho的树玩具的质量似乎不是很好,短短玩了几个星期,便掉漆了!
“简直是一场噩梦!”小Ho拿着树玩具眼含热泪道。
“这有什么好忧伤的,自己买点油漆刷一刷不就行了?”小Hi表示不能理解。
“还可以这样?”小Ho顿时兴高采烈了起来,立马跑出去买回来了油漆,但是小Ho身上的钱却不够——于是他只买回了有限的油漆,这些油漆最多能给M个结点涂上颜色,这就意味着小Ho不能够将他心爱的树玩具中的每一个结点都涂上油漆!
小Ho低头思索了半天——他既不想只选一部分结点补漆,也不想找小Hi借钱,但是很快,他想出了一个非常棒的主意:将包含1号结点的一部分连通的结点进行涂漆(这里的连通指的是这一些涂漆的结点可以互相到达并且不会经过没有涂漆的结点),然后将剩下的结点拆掉!
那么究竟选择哪些结点进行涂漆呢?小Ho想了想给每个结点都评上了分——他希望最后留下来,也就是涂漆了的那些结点的评分之和可以尽可能的高!
那么,小Ho该如何做呢?
输入
每个测试点(输入文件)有且仅有一组测试数据。
每组测试数据的第一行为两个整数N、M,意义如前文所述。
每组测试数据的第二行为N个整数,其中第i个整数Vi表示标号为i的结点的评分
每组测试数据的第3~N+1行,每行分别描述一根木棍,其中第i+1行为两个整数Ai,Bi,表示第i根木棍连接的两个小球的编号。
对于100%的数据,满足N<=10^2,1<=Ai<=N, 1<=Bi<=N, 1<=Vi<=10^3, 1<=M<=N
小Hi的Tip:那些用数组存储树边的记得要开两倍大小哦!
输出
对于每组测试数据,输出一个整数Ans,表示使得涂漆结点的评分之和最高可能是多少。
- 样例输入
-
10 4 370 328 750 930 604 732 159 167 945 210 1 2 2 3 1 4 1 5 4 6 4 7 4 8 6 9 5 10
- 样例输出
-
2977
f(t, m)表示,在以t为根的一棵树中,选出包含根节点t的m个连通的结点,能够获得的最高的评分,然后我们的答案就是f(1, M)!
这里不是和无限背包问题很像么?我可以不用单独的求解每一个f(t, m)而是针对于每一个t,同时求解它的f(t, 0..M),这样的话,我就可以把m视作背包容量,把每个子结点t_child都视作一件单位重量为1的物品,但是和背包问题不同的是,这件物品的总价值并不是单位价值乘以总重量,而是重量为m_child的该物品的价值为f(t_child, m_child),这样我就可以像无限背包问题一样,用这样的方法来进行求解!1 #include "iostream" 2 #include "vector" 3 #include "algorithm" 4 5 using namespace std; 6 7 #define MAXN 11111 8 vector<int> tree[MAXN]; 9 int value[MAXN]; 10 int dp[MAXN][MAXN]; //dp[i][j] 以i为根节点 保留j个点 11 int N,M; 12 13 14 15 void dfs(int root) 16 { 17 for (int i = 0;i < tree[root].size(); ++ i) 18 dfs(tree[root][i]); 19 dp[root][0] = 0; 20 dp[root][1] = value[root]; 21 for (int t_child = 0;t_child < tree[root].size(); ++ t_child) //把该结点当作树根,遍历所有子树 22 for (int m = M; m > 1; -- m) 23 for (int m_child = 1;m_child < m; ++ m_child) { 24 dp[root][m] = max(dp[root][m-m_child]+dp[ tree[root][t_child] ][m_child],dp[root][m]); 25 } 26 return; 27 } 28 29 int main() 30 { 31 cin >> N >> M; 32 int x, y, i; 33 for (i = 1;i <= N; ++ i) 34 cin >> value[i]; 35 while (cin >> x >> y) 36 tree[x].push_back(y); 37 dfs(1); 38 cout << dp[1][M] << endl; 39 return 0; 40 }