码迷,mamicode.com
首页 > 其他好文 > 详细

刷油漆(树形DP)

时间:2015-02-20 16:19:23      阅读:151      评论:0      收藏:0      [点我收藏+]

标签:

问题描述:

有一棵树,树上节点编号1~n,其中节点1为根节点,树上的每个节点有其对应的一个价值。现在要减掉一些枝桠,只留下m个节点的一棵树(必须包含根节点),为这m个节点着色,约束条件是要使剩下m个节点的价值之和最大化。

算法思路:

状态定义:dp[x][j]表示以节点x为根的子树中,着色节点数目为j时,从这棵子树中所能获得的最大价值。那么dp[1][m]即为所求。

状态转移:设节点y为节点x的子节点,那么dp[x][j] = max(dp[x][j], dp[y][k]+dp[x][j-k]),其中1<=k<j。

整体思路类似于完全背包。

我的代码:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <vector>
 4 #include <cstring>
 5 
 6 using namespace std;
 7 
 8 #define MAXN 105
 9 
10 int dp[MAXN][MAXN], n, m, v[MAXN];
11 bool vis[MAXN];
12 struct Tree
13 {
14     vector<int> t[MAXN];
15     void init(int n)
16     {
17         for(int i=1; i<=n; ++i) t[i].clear();
18         memset(&vis[1], 0, n);
19     }
20     void addEdge(int a, int b)
21     {
22         t[a].push_back(b);
23         t[b].push_back(a);
24     }
25     void solute(int x)
26     {
27         vis[x] = true;
28         memset(dp[x], 0, (m+1)*sizeof(int));
29         dp[x][1] = v[x];
30         for(int i=0; i<t[x].size(); ++i)
31         {
32             int y = t[x][i];
33             if(!vis[y])
34             {
35                 solute(y);
36                 for(int j=m; j>=2; --j) //注意这里的遍历顺序
37                 for(int k=1; k<j; ++k) dp[x][j] = max(dp[x][j], dp[x][j-k]+dp[y][k]);
38             }
39         }
40     }
41 }tree;
42 
43 int main()
44 {
45     while(cin>>n>>m)
46     {
47         for(int i=1; i<=n; ++i) cin>>v[i];
48         tree.init(n);
49         for(int i=0; i<n-1; ++i)
50         {
51             int a, b;
52             cin>>a>>b;
53             tree.addEdge(a, b);
54         }
55         tree.solute(1);
56         cout<<dp[1][m]<<endl;
57     }
58 
59     return 0;
60 }

题目来源:http://hihocoder.com/problemset/problem/1055

刷油漆(树形DP)

标签:

原文地址:http://www.cnblogs.com/pczhou/p/4296564.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!