BZOJ4753: [Jsoi2016]最佳团体

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 844  Solved: 318
[Submit][Status][Discuss]

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)$

#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;
}

原文地址:https://www.cnblogs.com/zwfymqz/p/8456201.html

时间: 2024-10-01 00:34:11

BZOJ4753: [Jsoi2016]最佳团体的相关文章

【bzoj4753】[Jsoi2016]最佳团体 分数规划+树形背包dp

题目描述 JSOI信息学代表队一共有N名候选人,这些候选人从1到N编号.方便起见,JYY的编号是0号.每个候选人都由一位编号比他小的候选人Ri推荐.如果Ri=0则说明这个候选人是JYY自己看上的.为了保证团队的和谐,JYY需要保证,如果招募了候选人i,那么候选人Ri"也一定需要在团队中.当然了,JYY自己总是在团队里的.每一个候选人都有一个战斗值Pi",也有一个招募费用Si".JYY希望招募K个候选人(JYY自己不算),组成一个性价比最高的团队.也就是,这K个被JYY选择的候

P4322 [JSOI2016]最佳团体

01分数规划+树形dp,其实很好想,题也不难. 题干: 题目描述 JSOI 信息学代表队一共有 NNN 名候选人,这些候选人从 111 到 NNN 编号.方便起见,JYY 的编号是 000 号.每个候选人都由一位编号比他小的候选人RiR_iRi? 推荐.如果 Ri=0R_i = 0Ri?=0?,则说明这个候选人是 JYY 自己看上的. 为了保证团队的和谐,JYY 需要保证,如果招募了候选人 iii,那么候选人 RiR_iRi? 也一定需要在团队中.当然了,JYY 自己总是在团队里的.每一个候选人

BZOJ.4753.[JSOI2016]最佳团体(01分数规划 树形背包DP)

题目链接 \(Description\) 每个点有费用si与价值pi,要求选一些带根的连通块,总大小为k,使得 \(\frac{∑pi}{∑si}\) 最大 \(Solution\) 01分数规划,然后dp,设f[i][j]表示i子树选j个的最大权值和,直接暴力背包转移即可 在枚举子节点选的数量时,假设x有1.2.3.4四个子节点,复杂度为 \(1*sz[1]+sz[1]*sz[2]+(sz[1]+sz[2])*sz[3]+(sz[1]+sz[2]+sz[3])*sz[4]\) 相当于每对点在L

[JSOI2016]最佳团体

嘟嘟嘟 01分数规划+树形背包. 然后就没了. 结果我调了半天,原因还是树形背包不熟练. 我是用dfs序求的,转化的时候,是dp[i][j]转化到dp[i + 1][j + 1]或dp[i +siz[pos[i]]][j],而不是像普通的dp从别的状态转化到dp[i][j],所以最后的答案应该考虑到dp[n + 1][m + 1],而不是只到n,而且初始化的时候也要到n + 1这一层.这也就是我为啥总WA第3个点. 1 #include<cstdio> 2 #include<iostre

bzoj4753 最佳团体

题目描述 JSOI 信息学代表队一共有 NN 名候选人,这些候选人从 11 到 NN 编号.方便起见,JYY 的编号是 00 号.每个候选人都由一位编号比他小的候选人R_iRi? 推荐.如果 R_i = 0Ri?=0?,则说明这个候选人是 JYY 自己看上的. 为了保证团队的和谐,JYY 需要保证,如果招募了候选人 ii,那么候选人 R_iRi? 也一定需要在团队中.当然了,JYY 自己总是在团队里的.每一个候选人都有一个战斗值 P_iPi? ,也有一个招募费用 S_iSi? .JYY 希望招募

【2018.10.1】【JSOI2016】最佳团体(bzoj4751)

一看到“比值”最大(性价比最高)就知道跟分数规划有关系了.(这里讲过分数规划) 然后看到 要选一个候选人 必须选他的前置,画画图就知道是一棵树. 所以这道题是二分比值,然后判断在树上能否得到这个答案. 那怎么判断? 这篇的T1讲过,典型的树上背包,像那道T1一样在树上暴力转移即可.其实这题的父子依赖性质跟那道T1差不多,因为连通块就是一片父子的依赖关系(当然最上边的根节点的祖先是还没处理到的). 那树上每个点都要遍历一下它的所有儿子,对于每个儿子还要枚举以这个儿子为根的子树中选出的点. 原文地址

#2071. 「JSOI2016」最佳团体

\(01\)分数规划不能直接套板子了,窝一开始想着用什么简单的方法缩点(每个点只有一个入度啊)然后跑拓扑图求解(保存每个点的最优值,通过牛顿迭代减少运算次数),问题是这样还要考虑人数,可不可做都不知道.转念一想,既然每个点只有一个入度,那么环从\(0\)号点\(jyy(orz)\)开始是肯定无法到达的(无法从任何一个点进入环).题目没说不可行就一定是可行的(雾),直接从\(0\)号点遍历即可,自然而然的拓扑图且还有个容易操作的性质,任意两条路不会汇合,理由如上,路只能分散,这不就是颗树吗?实现的

「JSOI2016」最佳团体

01分数规划 显然可以二分最大比值x,来验证是否可行 记当前比值为x,总战斗值为P与总招募费用为S 则 P - x*S >= 0 设 wi = pi - x*si 即 w1 + w2 + ... + wk >= 0 就转化为选k个节点,它们的w值非负,树上简单地dp一下就可求得 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 2505; 5 6 double l, r = 1e4, mid, f

bzoj 4753 最佳团体

Written with StackEdit. Description \(JSOI\)信息学代表队一共有N名候选人,这些候选人从\(1\)到\(N\)编号.方便起见,\(JYY\)的编号是\(0\)号.每个候选人都由一位编号比他小的候选人\(R_i\)推荐.如果\(R_i=0\)则说明这个候选人是\(JYY\)自己看上的.为了保证团队的和谐,\(JYY\)需要保证,如果招募了候选人\(i\),那么候选人\(R_i\)"也一定需要在团队中.当然了,\(JYY\)自己总是在团队里的.每一个候选人都