【题解】[JSOI2016] 最佳团体(分数规划)

P4322 JSOI2016 最佳团体 - 洛谷 (luogu.com.cn)

每个候选人 依赖 ,且 ,所以依赖关系形成一棵以 为根的树。

题目要求:如果选 ,就必须选 。这就是典型的树形依赖 dp,选子节点必须先选父节点。

但题目要最大化的是 不是直接最大化 ,所以不能直接背包,需要二分比值答案。


设计 dp 状态:dp[i][j] 表示从 dfs 序第 i 个位置开始,选 j 个节点的最大权值和。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 2510;

double S[N], P[N]; int R[N];
vector<int> G[N];
int dfn[N], tsp, id[N], siz[N];
int K, n;
double w[N], dp[N][N];
// dp[i][j] 表示从 dfs 序第 i 个位置开始,选 j 个节点的最大权值和

void dfs(int x) {
	dfn[x] = tsp;
	id[tsp] = x;
	tsp ++;
	siz[x] = 1;
	for (int y : G[x]) {
		dfs(y);
		siz[x] += siz[y];
	}
}

bool check(double x) {
	for (int i = 1; i <= n; i ++) {
		w[i] = P[i] - x * S[i];
	}
	w[0] = 0;
	for (int i = 0; i <= n + 1; i ++) {
		for (int j = 0; j <= K + 1; j ++) {
			dp[i][j] = -1e18;
		}
	}
	dp[n + 1][0] = 0;
	
	for (int i = n; i >= 0; i --) {   // 照 dfs 序从后往前遍历,也就是从叶子到根 
		int u = id[i];   // 当前 dfs 序对应的节点 
		for (int j = 0; j <= K + 1; j ++) {
			if (j >= 1) {
				dp[i][j] = max(dp[i][j], dp[i + 1][j - 1] + w[u]);
				// 当选了 u 节点,就可以从 u 的第一个孩子节点 i + 1 处转移 dp 
			}
			if (i + siz[u] <= n + 1) {
				dp[i][j] = max(dp[i][j], dp[i + siz[u]][j]);
				// 不选 u 节点,就只能从第一个不是 u 节点孩子转移,即跳过 u 的整个子树 
			}
			
			// 叶子节点没有孩子的特殊情况,上面两种分讨也包含了 
		}
	}
	/*
	假设某个叶子节点 v 被选中了
	在 dfs 序中,v 一定位于它所有祖先的子树区间内
	要从 dfs 序的起点走到 v,必须依次经过它的父节点、祖父节点......直到根

	在递推过程中,如果某个祖先 u 没有被选,那么根据情况一, 
	我们会直接跳过 u 的整个子树,根本不会进入 v 所在的区间
	因此 v 不可能被选中
	*/
	
	return (dp[0][K + 1] >= 0);   // 加上 0 就多选一个 
}

int main () {
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	cin >> K >> n;
	for (int i = 1; i <= n; i ++) {
		cin >> S[i] >> P[i] >> R[i];
		G[R[i]].push_back(i);
	}
	
	tsp = 0;
	dfs(0);
	
	double l = 0, r = 10000;
	// 小数点后三位精确,也就是 10000000 的精确度
	// 2 ^ 50 完全够   
	for (int i = 0; i <= 50; i ++) {
		double mid = (l + r) / 2;
		if (check(mid)) {
			l = mid;
		}
		else {
			r = mid;
		}
	}
	
	cout << fixed << setprecision(3) << l << "\n";
	
	
	return 0;
}
相关推荐
殷色玫瑰12 分钟前
C++ string类详解:常用接口、字符串操作与模拟实现
java·linux·c语言·开发语言·数据结构·c++
李游Leo15 分钟前
HarmonyOS 7 + Spatial Recon Kit-C++:3DGS 高斯参数的非有限值隔离与可渲染性门禁【鸿蒙心迹】
开发语言·c++·3d·harmonyos
Evand J21 分钟前
【MATLAB例程】三维RRT+APF路径规划与AOA-TDOA融合定位算法。附代码的下载链接
算法·matlab·路径规划·rrt·tdoa·apf·aoa
海绵宝宝转agent1 小时前
leetCode100算法开源笔记分享
笔记·算法
jimy11 小时前
基类没有虚析构函数,基类指针删除派生类对象,行为是未定义的
开发语言·c++
写后端的胖头鱼1 小时前
时间复杂度 & 空间复杂度
java·数据结构·算法·时间复杂度·空间复杂度
hahaha60162 小时前
黑体轨迹和色温--光源白点
人工智能·嵌入式硬件·算法·计算机视觉
海绵宝宝转agent2 小时前
基于Redis ZSet+AOP+注解实现限流注解算法
数据库·redis·算法
xlq223222 小时前
全面复习2
c++
无名猿2 小时前
移动构造与移动赋值:把资源偷过来
c++·性能优化·内存管理·现代c++·语法基础