int n,m;
int s[2505],p[2505],r[2505],size[2505];
double eps=1e-6;//设置二分精度
double v[2505],f[2505][2505];
vector<int> q[2505];
inline void dfs(int x){
f[x][0]=0;f[x][1]=v[x];
for(int i=2;i<=m;i++)f[x][i]=-1e9;
//初始化,这个很显然吧
size[x]=1;
//size数组表示以x为根节点的子树中的子节点的数量
//把x视作以x为根节点的子树中的子节点,所以初始值为1
//用于优化树形DP,不优化T飞5个点
//不懂的话,底下推荐的第二篇博客有提到
for(int i=0;i<q[x].size();i++){
int y=q[x][i];
dfs(y);
for(int j=size[x];j>=1;j--)
for(int k=0;k<=size[y];k++){
if(j+k>m)break;//优化
f[x][j+k]=max(f[x][j+k],f[x][j]+f[y][k]);
}
size[x]+=size[y];
}
}
inline bool check(double mid){
for(int i=1;i<=n;i++)
v[i]=p[i]-s[i]*mid;
//记得根据mid更新每个人的价值
dfs(0);//从根节点开始遍历整个树
return f[0][m]>=0;//判定
}
int main(){
m=read();n=read();
m++;
//因为0号节点必选,所以相当于我们要选择m+1个节点
for(int i=1;i<=n;i++){
s[i]=read();
p[i]=read();
r[i]=read();
q[r[i]].push_back(i);
}
//我直接vector存图了,也可以用链式前向星
double l=0,r=1e6,mid;
while(l+eps<r){
mid=(l+r)/2.0;
if(check(mid))l=mid;
else r=mid;
}
printf("%.3lf\n",l);
return 0;
}
原文:https://www.cnblogs.com/PPXppx/p/10370155.html