前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >BZOJ4753: [Jsoi2016]最佳团体

BZOJ4753: [Jsoi2016]最佳团体

作者头像
attack
发布2018-04-11 10:46:55
6610
发布2018-04-11 10:46:55
举报

Description

JSOI信息学代表队一共有N名候选人,这些候选人从1到N编号。方便起见,JYY的编号是0号。每个候选人都由一位

编号比他小的候选人Ri推荐。如果Ri=0则说明这个候选人是JYY自己看上的。为了保证团队的和谐,JYY需要保证,

如果招募了候选人i,那么候选人Ri"也一定需要在团队中。当然了,JYY自己总是在团队里的。每一个候选人都有

一个战斗值Pi",也有一个招募费用Si"。JYY希望招募K个候选人(JYY自己不算),组成一个性价比最高的团队。

也就是,这K个被JYY选择的候选人的总战斗值与总招募总费用的比值最大。

Input

输入一行包含两个正整数K和N。

接下来N行,其中第i行包含3个整数Si,Pi,Ri表示候选人i的招募费用,战斗值和推荐人编号。

对于100%的数据满足1≤K≤N≤2500,0<"Si,Pi"≤10^4,0≤Ri<i

Output

输出一行一个实数,表示最佳比值。答案保留三位小数。

Sample Input

1 2 1000 1 0 1 1000 1

Sample Output

0.001

HINT

2017.9.12新加数据一组 By GXZlegend

Source

应该是比较裸的题目

01分数规划+树形依赖背包。

01分数规划的话按照套路二分检验,注意设置好精度

树形依赖背包注意在枚举的时候上限应该在枚举之后更改否则会被卡成O(N^3\log ans)

代码语言:javascript
复制
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=1e6+10,INF=1e4+10;
inline char nc()
{
    static char buf[MAXN],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXN,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    char c=nc();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=nc();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=nc();}
    return x*f;
}
int N,K;
int S[MAXN],P[MAXN],R[MAXN];
struct node
{
    int u,v,nxt;
}edge[MAXN];
int head[MAXN];
int num=1;
inline void AddEdge(int x,int y)
{
    edge[num].u=x;
    edge[num].v=y;
    edge[num].nxt=head[x];
    head[x]=num++;
}
double dp[2501][2501],/*i处,选了j个*/siz[MAXN],w[MAXN];
void find(int now)
{
    siz[now]=1;
    for(int i=head[now];i!=-1;i=edge[i].nxt)
        find(edge[i].v),siz[now]+=siz[edge[i].v];
}
void dfs(int now)
{
    int tot=0,b=0;
    if(now) dp[now][1]=w[now],tot=1,b++;
    else dp[now][0]=0;
    for(int i=head[now];i!=-1;i=edge[i].nxt)
    {
        dfs(edge[i].v);
        for(int j=tot;j>=b;j--)//背包容量 
            for(int k=1;k<=siz[edge[i].v];k++)
                dp[now][j+k]=max(dp[now][j+k],dp[now][j]+dp[edge[i].v][k]);
        tot+=siz[edge[i].v];//必须在后面加 
    }
}
bool check(double val)
{
    memset(dp,0xc2,sizeof(dp));
    for(int i=1;i<=N;i++) w[i]=P[i]-val*S[i];
    dfs(0);
    return dp[0][K]>=0;
}
int main()
{
    #ifdef WIN32
    freopen("a.in","r",stdin);
    #else 
    #endif
    memset(head,-1,sizeof(head));
    K=read(),N=read();
    for(int i=1;i<=N;i++)
    {
        S[i]=read(),P[i]=read(),R[i]=read();
        AddEdge(R[i],i);
    }
    find(0);
    double l=0,r=INF;
    double ans=0;
    while(r-l>1e-5)
    {
        double mid=(l+r)/2;
        if(check(mid)) l=mid;
        else r=mid;    
    }
    printf("%.3lf",(l+r)/2);
     return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-02-21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Description
  • Input
  • Output
  • Sample Input
  • Sample Output
  • HINT
  • Source
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档