http://www.acm.cs.ecnu.edu.cn/problem.php?problemid=2103
树型dp + 分组背包。
dp[u][V]表示 对于以根为u的子树、剩余pow为V(看作容量)时能得到的最优解,那么:
对于u的某一个状态dp[u][k]:
其子树vi有 size( dp[vi][j] ) 个状态,但仅有一个状态可以转移给 dp[u][k] ,所以必须以子树为单位分组。
关于分组背包,详细请看:
http://blog.csdn.net/nywsp/article/details/7737158
1 #include<map> 2 #include<set> 3 #include<list> 4 #include<cmath> 5 #include<ctime> 6 #include<queue> 7 #include<stack> 8 #include<cctype> 9 #include<cstdio> 10 #include<string> 11 #include<vector> 12 #include<cstdlib> 13 #include<cstring> 14 #include<iostream> 15 #include<algorithm> 16 #define MAXN 105 17 using namespace std; 18 19 int dp[MAXN][MAXN], v[MAXN]; 20 int c[MAXN], w[MAXN]; 21 int ans; 22 vector<int> g[MAXN]; 23 24 void dfs(int u, int pu){ //分组背包,一棵子树为一组 25 v[u] = 1; 26 if(pu-c[u] < 0) 27 return ; 28 for(int j=c[u]; j<=pu; j++) 29 dp[u][j] = w[u]; 30 for(int i=0; i<g[u].size(); i++){ //组数 31 if(v[g[u][i]]) 32 continue; 33 dfs(g[u][i], pu-c[u]); 34 for(int j=pu; j>=c[u]; j--) //注意此for逆序,且在中间 35 for(int k=c[g[u][i]]; k<=j-c[u]; k++) //每组至多只取一个 36 dp[u][j] = max(dp[u][j], dp[u][j-k]+dp[g[u][i]][k]); 37 } 38 } 39 40 int main() 41 { 42 int n, p; 43 while(cin >> n >> p){ 44 if(n == 0){ 45 printf("0 "); 46 continue; 47 } 48 for(int i=1; i<=n; i++) 49 scanf("%d%d", &c[i], &w[i]); 50 for(int i=1; i<=n-1; i++){ 51 int a, b; 52 scanf("%d%d", &a, &b); 53 g[a].push_back(b); 54 g[b].push_back(a); 55 } 56 int root=1; 57 memset(v, 0, sizeof(v)); 58 memset(dp, 0, sizeof(dp)); 59 dfs(root, p); 60 if(p < c[root]) 61 printf("0 "); 62 else 63 printf("%d ", dp[root][p]); 64 for(int i=1; i<=n; i++) 65 g[i].clear(); 66 } 67 68 return 0; 69 }