bzoj4753 最佳团体

题目描述

JSOI 信息学代表队一共有 NN 名候选人,这些候选人从 11 到 NN 编号。方便起见,JYY 的编号是 00 号。每个候选人都由一位编号比他小的候选人R_iRi? 推荐。如果 R_i = 0Ri?=0?,则说明这个候选人是 JYY 自己看上的。

为了保证团队的和谐,JYY 需要保证,如果招募了候选人 ii,那么候选人 R_iRi? 也一定需要在团队中。当然了,JYY 自己总是在团队里的。每一个候选人都有一个战斗值 P_iPi? ,也有一个招募费用 S_iSi? 。JYY 希望招募 KK 个候选人(JYY 自己不算),组成一个性价比最高的团队。也就是,这 KK 个被 JYY 选择的候选人的总战斗值与总招募费用的比值最大。

输入输出格式

输入格式:

输入一行包含两个正整数 KK 和 NN 。

接下来 NN 行,其中第 ii 行包含三个整数 S_iSi? , P_iPi? , R_iRi? , 表示候选人 ii 的招募费用,战斗值和推荐人编号。

输出格式:

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

这题涉及到了比值最大,最好用分数规划来解决。

我们需要求出pi和ri的比值最大,不妨设Σpi/Σri>=x  ,经过转移Σpi>=Σri*x => Σpi-Σri*x>=0. 由此可见,我们可以二分出来一个x使这个值>=0.

然后我们可以用树形DP来计算出最优值。

我们先DFS一遍得到每个树上节点的DFS序(时间戳),令f[i][j]为DFS序为i的点,取j个的最优值。

如果当前点取,说明自己的子树也可以取,所以f[i+1][j+1]=max(f[i+1][j+1],f[i][j]+val[i]);

如果当前点不取,说明要取到下一颗树,我们记录size[i]代表以i为根的子树的大小。根据DFS序的性质,我们知道下一颗和自己平行的子树的DFS序为i+size.

所以转移方程是:f[i+size[i]][j]=max(f[i+size[i]][j],f[i][j]);

// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <stack>
#define in(a) a=read()
#define MAXN 200020
#define REP(i,k,n) for(int i=k;i<=n;i++)
using namespace std;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())
        if(ch==‘-‘)
            f=-1;
    for(;isdigit(ch);ch=getchar())
        x=x*10+ch-‘0‘;
    return x*f;
}
int k,n;
int INF=99999999;
double p[2510],s[2510];
int total=0,to[2520],nxt[2510],head[2510];
int cnt=0,dfn[2510],ind[2510],size[2510];
double f[2510][2510],val[2510];
inline void adl(int a,int b){
    total++;
    to[total]=b;
    nxt[total]=head[a];
    head[a]=total;
    return ;
}
inline void DFS(int u){
    dfn[u]=cnt;
    ind[cnt++]=u;
    size[u]=1;
    for(int e=head[u];e;e=nxt[e]){
        DFS(to[e]);
        size[u]+=size[to[e]];
    }
    return ;
}
inline double DP(double x){
    //cout<<x<<endl;
    REP(i,1,n){
        val[i]=p[ind[i]]-x*s[ind[i]];
        //cout<<ind[i]<<" "<<val[i]<<endl;
    }
    REP(i,1,n+1)
        REP(j,0,k+1)
            f[i][j]=-INF;
    REP(i,0,n)
        REP(j,0,min(i,k+1)){
            f[i+1][j+1]=max(f[i+1][j+1],f[i][j]+val[i]);
            f[i+size[ind[i]]][j]=max(f[i+size[ind[i]]][j],f[i][j]);
        }
    /*REP(i,0,n){
        REP(j,0,min(i,k+1))
            cout<<f[i][j]<<" ";
        cout<<endl;
    }*/
    return f[n+1][k+1];
}
int main(){
    in(k);in(n);
    int a;
    double maxn=-INF;
    REP(i,1,n){
        scanf("%lf%lf%d",&s[i],&p[i],&a);
        adl(a,i);
        maxn=max(maxn,p[i]);
    }
    DFS(0);
    val[0]=0.0;
    double left=0.0,right=maxn;
    while(right-left>0.00001){
        double mid=(left+right)/2.0;
        //cout<<left<<" "<<right<<" "<<mid<<endl;
        if(DP(mid)>=0.00001)  left=mid;
        else  right=mid;
    }
    printf("%.3lf",left);
    return 0;
}
/*
2 4
1 2 0
2 2 0
1 3 1
2 3 1
*/

 

原文地址:https://www.cnblogs.com/jason2003/p/9737461.html

时间: 2024-11-03 22:48:55

bzoj4753 最佳团体的相关文章

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

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

BZOJ4753: [Jsoi2016]最佳团体

Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 844  Solved: 318[Submit][Status][Discuss] Description JSOI信息学代表队一共有N名候选人,这些候选人从1到N编号.方便起见,JYY的编号是0号.每个候选人都由一位 编号比他小的候选人Ri推荐.如果Ri=0则说明这个候选人是JYY自己看上的.为了保证团队的和谐,JYY需要保证, 如果招募了候选人i,那么候选人Ri"也一定需要在团队中.当然了,JYY

bzoj 4753 最佳团体

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

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

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

[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

#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