$n leq 2500$个人选$m leq n$个,每人有花费有收益,还有依赖人,选他前必须选依赖人。问最大的收益花费比。
01分数规划。$sum p_i-ts_i leq 0$,这式子成立时要把$t$调小,不成立时要把$t$调大,我们希望$t$大,就尽可能让他不成立,所以就尽可能让左边大。
然后就是树形依赖背包。$f(i,j)$--dfs序上$i$处往后选$j$个的最大值,$f(i,j)=max(f(i+1,j-1)+val_i,f(k,j))$,其中$k$是$i$子树的最后一个节点的下一位。
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 //#include<math.h> 5 //#include<queue> 6 //#include<vector> 7 #include<algorithm> 8 //#include<iostream> 9 //#include<assert.h> 10 using namespace std; 11 12 int n,m; 13 #define maxn 2511 14 double f[maxn][maxn],val[maxn]; 15 int p[maxn],s[maxn]; 16 17 struct Edge{int to,next;}edge[maxn<<1]; int first[maxn],le=2; 18 void in(int x,int y) {Edge &e=edge[le]; e.to=y; e.next=first[x]; first[x]=le++;} 19 int id[maxn],rr[maxn],len=0; 20 void predfs(int x,int fa) 21 { 22 id[++len]=x; 23 for (int i=first[x];i;i=edge[i].next) 24 { 25 Edge &e=edge[i]; if (e.to==fa) continue; 26 predfs(e.to,x); 27 } 28 rr[x]=len; 29 } 30 31 bool check(double x) 32 { 33 for (int i=1;i<=n;i++) val[i]=p[i]-x*s[i]; 34 f[len][0]=0; f[len][1]=val[id[len]]; for (int i=2;i<=n+1;i++) f[len][i]=-1e18; 35 for (int i=len-1;i>1;i--) 36 { 37 f[i][0]=0; 38 for (int j=1;j<=len;j++) 39 { 40 f[i][j]=f[i+1][j-1]+val[id[i]]; 41 if (rr[id[i]]<len) f[i][j]=max(f[i][j],f[rr[id[i]]+1][j]); 42 } 43 } 44 return f[2][m]<=0; 45 } 46 47 int main() 48 { 49 scanf("%d%d",&m,&n); 50 for (int i=1,x;i<=n;i++) scanf("%d%d%d",&s[i],&p[i],&x),in(x,i); 51 predfs(0,-1); 52 53 double L=0,R=1e4+3; 54 while (R-L>1e-4) 55 { 56 double mid=(L+R)/2; 57 if (check(mid)) R=mid; else L=mid; 58 } 59 printf("%.3lf ",L); 60 return 0; 61 }