[洛谷-P4322][JSOI2016]最佳团体(树形DP + 01分数规划)
创始人
2025-05-28 02:48:24

一、问题

题目描述

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

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

输入格式

输入一行包含两个正整数 KKK 和 NNN 。

接下来 NNN 行,其中第 iii 行包含三个整数 SiS_iSi​ , PiP_iPi​ , RiR_iRi​ ,
表示候选人 iii 的招募费用,战斗值和推荐人编号。

输出格式

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

样例 #1

样例输入 #1

1 2
1000 1 0
1 1000 1

样例输出 #1

0.001

提示

对于100%的数据满足1≤K≤N≤25001≤K≤N≤25001≤K≤N≤2500,0 000 ≤≤≤ RiR_iRi​ <<< iii

二、分析

这道题其实一眼看过去就是一个树形背包DP,但是这道题唯一特别的就是其中涉及到了分数。当我们求一个分数的最值的时候,我们通常使用的是二分

1、分数规划

当题目中让我们求:∑ai∑bi\frac{\sum a_i}{\sum b_i}∑bi​∑ai​​的最大值的时候,我们应该怎么做呢?

不妨设:
∑ai∑bi=x\frac{\sum a_i}{\sum b_i}=x∑bi​∑ai​​=x

那么就有:
∑ai=xmax∗∑bi\sum a_i = x_{max} * \sum b_i ∑ai​=xmax​∗∑bi​

即:

∑ai−xmax∑bi=0\sum a_i - x_{max}\sum b_i=0 ∑ai​−xmax​∑bi​=0

我们可以将这几个求和融合一下:

∑(ai−x∗bi)=0\sum(a_i-x*b_i)=0 ∑(ai​−x∗bi​)=0

因此,我们可以让括号内的式子是CiC_iCi​

我们会发现一个特点∑Ci\sum C_i∑Ci​是关于xxx的单调函数,因此我们可以使用二分,而二分中的checkcheckcheck函数其实就是利用树形DP求出上面求和式的最大值,然后进行判断。

我们这里用到的二分是浮点数二分

整个过程的时间复杂度是O(n2logn)O(n^2logn)O(n2logn)的。(树形背包DP看似是O(n3)O(n^3)O(n3)的,但实际上当我们对其上下界进行优化后,可以到达O(n2)O(n^2)O(n2))。

2、树形DP

状态表示

f[u][j]f[u][j]f[u][j]表示在以uuu为根的树(包括uuu)中选jjj个节点,∑ci\sum c_i∑ci​的最大值。

状态转移

f[u][j]=max(f[u][j],f[u][j−q]+f[son][q])f[u][j]=max\bigg(f[u][j],f[u][j-q]+f[son][q]\bigg) f[u][j]=max(f[u][j],f[u][j−q]+f[son][q])

初末状态

f[u][1]f[u][1]f[u][1]表示选一个,所以就是f[u][1]=c[u]f[u][1]=c[u]f[u][1]=c[u]
f[u][0]f[u][0]f[u][0]表示选0个,所以就是f[u][0]=0f[u][0]=0f[u][0]=0

由于题目中选000节点不算进我们方案,但是我们在计算的时候,还是要算入我们的答案的,所以我们代码中选择的实际上是k+1k+1k+1个点。最终的状态即:f[0][k+1]f[0][k+1]f[0][k+1]

三、代码

#include
#define endl '\n'
#define INF  0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair pii;
const int N = 2500 + 10;
double f[N][N];
double p[N], s[N], c[N];
int siz[N];
vectoredge[N];
int n, k;//f[u][j] => 在以u为根的树中,选择j个点,c的和的最大值。void cal_siz(int u)
{siz[u] = 1;for(int i = 0; i < edge[u].size(); i ++){cal_siz(edge[u][i]);siz[u] += siz[edge[u][i]];}
}void dp(int u)
{f[u][0] = 0.0;f[u][1] = c[u];for(int i = 0; i < edge[u].size(); i ++ ){int son = edge[u][i];dp(son);for(int j = min(siz[u], k + 1); j >= 0; j -- )for(int q = 0; q <= min(siz[son], j - 1); q ++ ){if(f[u][j - q] == -INF || f[son][q] == -INF)continue;	f[u][j] = max(f[u][j], f[son][q] + f[u][j - q]);}}
}bool check(double mid)
{for(int i = 0; i <= n; i ++ )for(int j = 0; j <= k + 1; j ++ )f[i][j] = -INF;for(int i = 1; i <= n; i ++ )c[i] = p[i] - mid * s[i];dp(0);return f[0][k + 1] >= 0.0;
}double find()
{double l = 0.0, r = 5000;while(r - l > 1e-9){double mid = (l + r) / 2;if(check(mid))l = mid;elser = mid;// cout << l << " " << r << endl;}return l;
}void solve()
{cin >> k >> n;for(int i = 1; i <= n; i ++ ){int fa;cin >> s[i] >> p[i] >> fa;edge[fa].push_back(i);}cal_siz(0);printf("%.3lf", find());
}int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);solve();
}

相关内容

热门资讯

Java发起同步和异步HTTP... 同步与异步概念辨析 同步(synchronous)和异步(...
Kubernetes安装与集群... 一、环境准备 1、机器环境前置条件 当前演示准备3台虚拟机环境,或者是3台阿里云服务器...
simscape仿真总结2-机... 最近用simscape进行机器人的仿真,记录和总结一下学习心得和踩过的坑。 参照B站...
Redis(一):数据结构-底... 前言 从本文开始,我将分享一下近期自学 Redis 的学习笔记,其中大部...
flask教程5:abort函... 文章目录一、abort()函数的使用1.传递状态码信息2.传递响应体消息二、自定义错误处理 app....
【玩转Jetson TX2 N... 1 VMware14 Workstation Pro安装 如果没有Ubuntu系统电脑,...
2023还有人不知道kuber... 文章目录Kubernetes(K8s)一、Openstack&VM1、**认识虚拟化****1.1*...
NOI2019模拟赛 T1牛油... 题目描述 牛油果是一种神秘的水果,其具有一个坚固程度x≥0x\geq 0x≥0...
嵌入式软件开发之Linux下C... 目录 前沿 Hello World! 编写代码 编译代码 GCC编译器  gcc 命...
云原生|Rancher与Ope... 目录一、Rancher(一)介绍(二)优点&...
如何突破卫星影像建模难点?重建... 日前,由重建大师生成的首个“珞珈三号01星”卫星影像三维模型一经发出,引...
L1-085 试试手气 L1... 我们知道一个骰子有 6 个面,分别刻了 1 到 6 个点。下面给你 6 个骰子的初始状...
SpringSecurity客... 概述 FilterChainProxy是spring-security的入口,包含默认...
数据结构--二叉树 目录1.树概念及结构1.1数的概念1.2数的表示2.二叉树概念及结构2.1二叉树的概念2.2数据结构...
Qt之QUrl和QUrlQue... QUrlQUrl 类提供了一个方便的接口使用 URLs。最常见的使用QUrl 的方式是通过构造函数来...
函数指针二三事 1 什么是函数指针? ​ 函数指针,顾名思义,它是一个指向...
[ 红队知识库 ] Windo... 🍬 博主介绍 👨‍🎓 博主介绍:大家好...
【PowerBI】PowerB... 目的: 陈述PowerBI连接Mysql数据库的坑。 方法1:直接使用【...
BI数据可视化|可自动刷新的可... BI数据可视化大屏和其他的BI报表一样,都是可用于日常的决策中,因此除了...
Linux 练习十二 (Lin... 文章目录1 计算机网络基础知识1.1 OSI参考模型和TCP/IP参考模型1.2 TCP 协议1.2...
SQL语言基础教学 | Mys... SQL语言基础教学SQL(Structured Query Languageÿ...
pandas数据分析(三) 书接pandas数据分析(二) 文章目录DataFrame数据处理与分...
DC-DC升压模块隔离高压稳压... 特点● 效率高达 80%● 2*2英寸标准封装● 单双电压输出● 价格低● 大于600V高压,稳压输...
Java【多线程基础2】 Th... 文章目录前言一、Thread类1, 构造方法2, 常用成员属性3, 常用成员方法3.1, start...
TDK| 电源——反激变压器设... 电源参数根据功率、输入输出的情况,我们选择反激电源拓扑。反激式变压器的优点有:1、 电...
Python:判断语句 目录一、布尔类型1.1定义1.2获取二、逻辑运算符2.1and运算符2.2or运算符2.2not运算...
协程池加disruptor加e... 先说一下disrutor和协程的实现。然后介绍服务器具体分析,以及迭代过程,项目困难,学到东西,压测...
selenium(2)----... 操作界面上的元素: 先选中元素再进行调用下面的方法 1)click(),点击对象 2)...
第九章:C语言数据结构与算法初... 系列文章目录 文章目录系列文章目录前言一、堆的定义二、堆的实现三、堆的接口函数1、初始化2、销毁3...
< Linux > 多线程(单... 目录 1、单例模式         饿汉方式实现单例模式         懒汉方式实现单例模式   ...