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 }