/* 题意: 一棵树(编号1-n),1是敌人出口(只有一个敌人)。 叶子节点是我军。在节点处装大炮。每个节点有 k 种大炮选择, 可是每个节点最多装一个大炮。每个大炮有一个花费和一个威力值。 你一共有m钱,怎么能使威力值最大。敌人去攻击哪个我军是任意的, 所以最大威力是每条路值和的最小值。大炮放在叶子节点也是管用的。 思路: 每个节点所能得到的power应该去儿子节点的最小值, 然后加上本节点建塔所得的power。因为你要保证一定能守得住。 所以得考虑最坏情况,然后尽量最优安排,使这个最坏情况尽量的好。 */ #include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; const int maxn=1002; const int maxm=202; const int inf=1<<29; int n,m,t,num,dp[maxn][maxm],hp[maxn][maxm]; vector<int>p[maxn]; void init() { int i,j; for(i=0; i<=n; i++) { p[i].clear(); for(j=0; j<=m; j++) { hp[i][j]=0; dp[i][j]=inf; } } } void dfs(int u,int fa) { int i,j,k,v,cnt=p[u].size(); if(u!=1&&cnt==1)///叶子节点 { for(i=m; i>=0; i--) { dp[u][i]=hp[u][i]; } return; } for(i=0; i<cnt; i++) { v=p[u][i]; if(v==fa)continue; dfs(v,u); for(j=m; j>=0; j--) { int mmin=0; for(k=0; k<=j; k++)///找到孩子节点的最小值中的最大值 { mmin=max(mmin,min(dp[u][j-k],dp[v][k])); } dp[u][j]=mmin;///没有选择根节点 } } for(j=m; j>=0; j--)///根节点选择了一组数据 { for(k=0; k<=j; k++) { dp[u][j]=max(dp[u][j],dp[u][j-k]+hp[u][k]); } } } int main() { scanf("%d",&t); int i,j,u,v,cost,power; while(t--) { scanf("%d",&n); init(); for(i=1; i<n; i++) { scanf("%d%d",&u,&v); p[u].push_back(v); p[v].push_back(u); } scanf("%d",&m); for(i=1; i<=n; i++) { scanf("%d",&num); for(j=1; j<=num; j++) { scanf("%d%d",&cost,&power); hp[i][cost]=max(hp[i][cost],power); } } for(i=1; i<=n; i++) { for(j=1; j<=m; j++) { hp[i][j]=max(hp[i][j],hp[i][j-1]); } } dfs(1,0); printf("%d\n",dp[1][m]); } return 0; } /* 4 2 1 2 30 3 10 20 20 40 30 50 3 10 30 20 40 30 45 4 2 1 3 1 1 4 60 3 10 20 20 40 30 50 3 10 30 20 40 30 45 3 10 30 20 40 30 35 3 10 30 20 40 30 35 */