题目biu
树型依赖背包:传送门
题意:n个员工,要选k个员工,每个员工都有一个薪水和能力,要使得最终性价比最高。
由于这题要选上子节点就必须把父节点选上,我们很容易就想到了树型依赖背包。a[i]:代表能力,b[i]代表薪水
我们可以通过枚举一个答案mid,可以判断 ,来进行check。我们将公式进行简单变换就是这样,我们可以将(a[i]-mid*b[i])看成第i件物品的价值,而i件物品的重量就是1,在满足去子节点就要取上父亲节点的前提下,取上个k+1个物品的最大收益。
#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define sc(n) scanf("%d",&n)
#define SC(n,m) scanf("%d %d",&n,&m)
#define SZ(a) int((a).size())
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define drep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const double pi=acos(-1.0);
const double eps=1e-9;
const int maxn=3e3+5;
//il int add(int x,int y) {return x+y>=mod?x+y-mod:x+y;}
//il int mul(ll x,int y) {return x*y>=mod?x*y%mod:x*y;}
int k,n,a[maxn],b[maxn],w[maxn];
vector<int> eg[maxn];
int sz[maxn],st[maxn],dl[maxn],t=0;
il void dfs(int p){
sz[p]=1,st[p]=t++,dl[t-1]=p;
for(int to:eg[p]) dfs(to),sz[p]+=sz[to];
}
double v[maxn],dp[maxn][maxn];
il bool ck(double ta){
rep(i,1,n) v[i]=1.0*a[i]-1.0*b[i]*ta;
rep(i,0,n+2) rep(p,0,k+1) dp[i][p]=dp[i][p]=-inf;
dp[n+1][0]=0.0;
for(int i=n;i>=0;--i){
int x=dl[i];
for(int p=0;p<=k+1;++p){
if(p<w[x]) dp[i][p]=max(dp[i+sz[x]][p],dp[i][p]);
else dp[i][p]=max(max(dp[i+sz[x]][p],dp[i+1][p-w[x]]+v[x]),dp[i][p]);
}
}
if(dp[0][k+1]-0.0>eps) return true;
else return false;
}
int main(){
SC(k,n);
int x;
rep(i,1,n){
SC(b[i],a[i]),sc(x);
eg[x].pb(i);
}
dfs(0);
rep(i,0,n) w[i]=1;
double le=0.0,ri=inf,ans;
while(abs(ri-le)>eps){
double mid=(ri+le)/2;
if(ck(mid)){
ans=mid;
le=mid;
}
else ri=mid;
}
printf("%.3lf\n",ans);
return 0;
}