BZOJ 4753: [Jsoi2016]最佳团体 01分数规划+树形DP

显然01分数规划转成二分答案+判断是否大于 0 的问题. 

这个题有一个坑点:不止根节点的父亲可能是 0 号节点(0号节点也是不能省略的) 

code: 

#include <cstdio> 
#include <string> 
#include <cstring> 
#include <iostream>  
#include <algorithm>   
#define N 2600  
#define eps 0.0001  
using namespace std;  
void setIO(string s) 
{
    string in=s+".in"; 
    string out=s+".out"; 
    freopen(in.c_str(),"r",stdin); 
    // freopen(out.c_str(),"w",stdout);   
}            
int edges,n,K;     
double v[N],f[N][N],ff[N];   
int fa[N],si[N],pi[N],hd[N],to[N],nex[N],size[N];   
void add(int u,int v) 
{ 
    nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;  
}       
void dfs(int x) 
{
    size[x]=1;      
    f[x][1]=v[x];         
    for(int i=hd[x];i;i=nex[i]) 
    {
        int y=to[i];   
        dfs(y);      
        memcpy(ff,f[x],sizeof(f[x]));            
        for(int j=1;j<=size[x];++j) 
            for(int k=1;k<=size[y];++k) 
                ff[j+k]=max(ff[j+k],f[x][j]+f[y][k]);         
        size[x]+=size[y];                                              
        for(int j=1;j<=size[x];++j) f[x][j]=ff[j];   
    }                         
}
int check(double mi) 
{
    for(int i=1;i<=n;++i)  v[i]=pi[i]-(double)1.0*mi*1.0*si[i];                  
    memset(f,0xc2,sizeof(f)),dfs(0);              
    return f[0][K+1]>=0;  
}
int main() 
{   
    // setIO("input");  
    int i,j;  
    scanf("%d%d",&K,&n);       
    for(i=1;i<=n;++i) 
    {
        scanf("%d%d%d",&si[i],&pi[i],&fa[i]),add(fa[i],i);                     
    }                   
    double l=0.0,r=10001.0;        
    for(;r-l>=eps;) 
    {   
        double mid=(l+r)*0.5;     
        if(check(mid)) l=mid;  
        else r=mid;   
    }    
    printf("%.3f\n",l);    
    return 0; 
}

  

posted @ 2020-01-02 16:23  EM-LGH  阅读(170)  评论(0编辑  收藏  举报