P4322 最佳团体
题目描述
题解
分数规划+树形背包判断
我们令dp[i][j]dp[i][j]dp[i][j]表示枚举到第iii个节点,选了jjj个人的最大值
那么就可以得出转移方程:dp[i][j+k]=max(dp[i][j+k],dp[i][j]+dp[w][k])dp[i][j+k]=max(dp[i][j+k],dp[i][j]+dp[w][k])dp[i][j+k]=max(dp[i][j+k],dp[i][j]+dp[w][k])kkk是iii的子节点
注意:
1,对double类型赋初值的方法
代码
#include<bits/stdc++.h>
#define M 2509
using namespace std;
int tot,n,k,first[M],to[M<<1],nxt[M<<1],size[M];
double l=0,r=10001,a[M],b[M],dp[M][M],A[M],B[M];
const double eps=1e-5;
int read(){
int f=1,re=0;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-'){f=-1,ch=getchar();}
for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
void add(int x,int y){
nxt[++tot]=first[x];
first[x]=tot;
to[tot]=y;
}
void dfs(int u,int fa){
size[u]=1,dp[u][0]=0,dp[u][1]=A[u];
for(int i=first[u];i;i=nxt[i]){
int v=to[i];
if(v==fa) continue;
dfs(v,u);
for(int j=1;j<=size[u]+size[v];j++) B[j]=dp[0][M-1];
for(int j=1;j<=size[u];j++)
for(int k=0;k<=size[v];k++)
B[j+k]=max(B[j+k],dp[u][j]+dp[v][k]);
size[u]+=size[v];
for(int j=1;j<=size[u];j++) dp[u][j]=B[j];
}
}
int main(){
k=read(),n=read();
for(int i=1;i<=n;i++){
a[i]=read(),b[i]=read();int x=read();
add(i,x),add(x,i);
}
while(r-l>eps){
double mid=(l+r)/2;
for(int i=1;i<=n;i++) A[i]=b[i]-a[i]*mid;
memset(dp,0xc2,sizeof(dp)),dfs(0,0);
if(dp[0][k+1]>eps) l=mid;
else r=mid;
} printf("%.3lf\n",r);
return 0;
}