背包专题小结
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; //树形DP //题意: n间房子,m个士兵;每个士兵可以在一个房间里解决20个bug,不足20个也要一个 // 士兵,这些房子是树形结构,每次到达一个房子,必须把它前面的房子里的bug解决 // 了; // 然后给n个房间的bug数,和解决这些bug得到的利益。 // 然后给的是房间的树形结构。 // 总是从编号为1的房间作为入口。 //解题思路: // 前向星存图,并不要存成树,存成一个图,还是双向的。 // struct Node { int now,to; }edge[105]; int cnt,head[105],vis[105]; void init() { cnt=0; memset(head,-1,sizeof(head)); memset(vis,0,sizeof(vis)); } void add(int no,int to) { edge[cnt].now=no; edge[cnt].to=head[to]; head[to]=cnt++; } int bug[105],p[105]; int n,m; int dp[105][105];//在i点放j人能得到的最多的能量; int dfs(int root) { vis[root]=1; int cost = (bug[root]+19)/20; for(int i=cost;i<=m;i++) dp[root][i]=p[root];//小于cost的无法获得经验; for(int i=head[root]; i!=-1; i=edge[i].to) { int v=edge[i].now; if(!vis[v]) { dfs(v); for(int j=m;j>=cost;j--) for(int k=1;j+k<=m;k++) if(dp[v][k]) dp[root][j+k]= max(dp[root][j+k],dp[root][j]+dp[v][k]); } } } int main() { while(scanf("%d%d",&n,&m)!=EOF) { if(n==-1 && m ==-1) break; for(int i=1;i<=n;i++) scanf("%d%d",&bug[i],&p[i]); init(); for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y); add(y,x); } if(!m) { printf("0\n"); continue; } memset(dp,0,sizeof(dp)); dfs(1); printf("%d\n",dp[1][m]); } return 0; }