标签:
问题描述:
有一棵树,树上节点编号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
标签:
原文地址:http://www.cnblogs.com/pczhou/p/4296564.html