专题训练
1 #include<stdio.h> 2 #include<iostream> 3 #include<string.h> 4 #include<algorithm> 5 using namespace std; 6 const int MAXN=1010; 7 const int INF=0x3fffffff; 8 struct Node 9 { 10 int to; 11 int next; 12 }edge[MAXN*2]; 13 int tol; 14 int head[MAXN]; 15 int dp[MAXN][220]; 16 int price[MAXN][60]; 17 int power[MAXN][60]; 18 19 void init() 20 { 21 memset(head,-1,sizeof(head)); 22 tol=0; 23 } 24 void add(int a,int b) 25 { 26 edge[tol].to=b; 27 edge[tol].next=head[a]; 28 head[a]=tol++; 29 edge[tol].to=a; 30 edge[tol].next=head[b]; 31 head[b]=tol++; 32 } 33 int n,m; 34 int tmp[MAXN]; 35 void dfs(int u,int pre) 36 { 37 if(head[u]==-1||(edge[head[u]].to==pre&&edge[head[u]].next==-1))//叶子结点 38 {//叶子结点的条件不要错了!!!! 39 for(int i=0;i<=m;i++)dp[u][i]=0; 40 41 for(int i=0;i<=m;i++)tmp[i]=dp[u][i]; 42 //因为存在价格为0的点。所以倒序的DP并不能保证只取一件物品 43 for(int i=m;i>=0;i--) 44 { 45 for(int j=1;j<=price[u][0];j++) 46 if(price[u][j]<=i) 47 dp[u][i]=max(dp[u][i],tmp[i-price[u][j]]+power[u][j]); 48 49 tmp[i]=dp[u][i];//tmp数组是记录的dp的上一个状态 50 } 51 return; 52 } 53 for(int i=0;i<=m;i++) dp[u][i]=INF; 54 for(int i=head[u];i!=-1;i=edge[i].next) 55 { 56 int v=edge[i].to; 57 if(v==pre)continue; 58 dfs(v,u); 59 for(int j=m;j>=0;j--) 60 { 61 int t=0; 62 for(int k=0;k<=j;k++)//这里k一定要从0开始。 63 t=max(t,min(dp[u][j-k],dp[v][k])); 64 dp[u][j]=t; 65 } 66 } 67 68 69 for(int i=0;i<=m;i++)tmp[i]=dp[u][i]; 70 for(int i=m;i>=0;i--) 71 { 72 for(int j=1;j<=price[u][0];j++) 73 if(price[u][j]<=i) 74 dp[u][i]=max(dp[u][i],tmp[i-price[u][j]]+power[u][j]); 75 //和上面一样分组背包加了个tmp数组 76 tmp[i]=dp[u][i]; 77 } 78 } 79 int main() 80 { 81 int u,v; 82 int T; 83 scanf("%d",&T); 84 while(T--) 85 { 86 init(); 87 scanf("%d",&n); 88 for(int i=1;i<n;i++) 89 { 90 scanf("%d%d",&u,&v); 91 add(u,v); 92 } 93 scanf("%d",&m); 94 for(int i=1;i<=n;i++) 95 { 96 scanf("%d",&price[i][0]); 97 power[i][0]=price[i][0]; 98 for(int j=1;j<=price[i][0];j++) 99 { 100 scanf("%d%d",&price[i][j],&power[i][j]); 101 } 102 } 103 dfs(1,0); 104 printf("%d\n",dp[1][m]); 105 } 106 return 0; 107 }
时间: 2024-10-05 23:10:06