BZOJ1722: [Usaco2006 Mar] Milk Team Select 产奶比赛

n<=500的树上有点权(有正负),选若干个点使点权和>=X(<=1e6)并且相邻点的对数最多,输出相邻点最多多少对。

在n个点里选某权和的最多相邻点->在n个点里选某数量的相邻点使权和最大

f(i,j,0/1)--子树i中选j对相邻关系,不选/选择节点i的最大权和,

就是个背包嘛。不过注意一下背包枚举顺序即可。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 #include<algorithm>
 5 //#include<queue>
 6 //#include<iostream>
 7 using namespace std;
 8 
 9 int n,X;
10 #define maxn 1011
11 struct Edge{int to,next;}edge[maxn];int first[maxn],le=2,val[maxn];
12 void in(int x,int y) {Edge &e=edge[le];e.to=y;e.next=first[x];first[x]=le++;}
13 void insert(int x,int y) {in(x,y);in(y,x);}
14 int f[maxn][maxn][2];
15 int x;
16 const int inf=0x3f3f3f3f;
17 void dp(int x,int fa)
18 {
19     for (int i=1;i<=n;i++) f[x][i][0]=f[x][i][1]=-inf;
20     for (int i=first[x];i;i=edge[i].next)
21     {
22         const Edge &e=edge[i];if (e.to==fa) continue;
23         dp(e.to,x);
24         for (int j=n;j>=0;j--)
25             for (int k=0;k<=j;k++)
26             {
27                 f[x][j][1]=max(f[x][j][1],f[x][j-k][1]+max(k==0?-inf:f[e.to][k-1][1],f[e.to][k][0]));
28                 f[x][j][0]=max(f[x][j][0],f[x][j-k][0]+max(f[e.to][k][1],f[e.to][k][0]));
29             }
30     }
31     for (int j=n;j>=0;j--) f[x][j][1]+=val[x];
32 }
33 int main()
34 {
35     scanf("%d%d",&n,&X);
36     for (int i=1;i<=n;i++)
37     {
38         scanf("%d%d",&val[i],&x);
39         insert(x,i);
40     }
41     dp(0,-1);
42     int ans=n;
43     for (;ans>=0;ans--) if (f[0][ans][0]>=X) break;
44     printf("%d\n",ans);
45     return 0;
46 }
View Code

 

posted @ 2017-09-27 15:20  Blue233333  阅读(341)  评论(0编辑  收藏  举报