题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1011
思路:很明显的树形背包
定义dp[root][m]表示以root为根,派m个士兵的最优解,那么dp[root][m]=max(dp[root][m],dp[root][k]+dp[son][j]) k+j<=m son为root 的孩子
树形dp的思路一般就是着父亲和孩子节点之间的转移关系,然后从dfs到叶子节点,然后开始从叶子节点向上进行DP
最重要的就是建树和dfs求解的过程,如果掌握了怎样建树和怎样进行DP,那么树形DP就会发现很简单了。。。。
加油!!!ACMer
代码如下:
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 #define MAX 110 7 int n,m; 8 int dp[MAX][MAX]; 9 int tol; 10 class node 11 { 12 public: 13 int to; 14 int next; 15 }; 16 node edge[MAX*3]; 17 int head[MAX]; 18 int bugs[MAX]; 19 int brain[MAX]; 20 int vis[MAX]; 21 void Build_Tree(int u,int v) 22 { 23 edge[tol].to=v; 24 edge[tol].next=head[u]; 25 head[u]=tol++; 26 } 27 void init() 28 { 29 memset(head,-1,sizeof(head)); 30 memset(dp,0,sizeof(dp)); 31 memset(vis,0,sizeof(vis)); 32 memset(bugs,0,sizeof(bugs)); 33 memset(brain,0,sizeof(brain)); 34 tol=0; 35 } 36 void dfs(int root) 37 { 38 vis[root]=1; 39 int cost=(bugs[root]+19)/20;//important 40 for(int i=cost;i<=m;i++) 41 dp[root][i]=brain[root]; 42 for(int i=head[root];i!=-1;i=edge[i].next) 43 { 44 if(vis[edge[i].to]) continue; 45 int son=edge[i].to; 46 dfs(son); 47 48 for(int j=m;j>=cost;j--) 49 { 50 for(int k=1;k+j<=m;k++) 51 if(dp[son][k]) 52 dp[root][j+k]=max(dp[root][j+k],dp[son][k]+dp[root][j]); 53 } 54 } 55 } 56 int main() 57 { 58 while(scanf("%d%d",&n,&m)!=EOF) 59 { 60 if(n==-1||m==-1) break; 61 init(); 62 for(int i=1;i<=n;i++) 63 scanf("%d%d",&bugs[i],&brain[i]); 64 for(int i=1;i<n;i++) 65 { 66 int u,v; 67 scanf("%d%d",&u,&v); 68 Build_Tree(u,v); 69 Build_Tree(v,u); 70 } 71 if(m==0) {cout<<"0"<<endl;continue;} 72 dfs(1); 73 cout<<dp[1][m]<<endl; 74 75 } 76 return 0; 77 }