洛谷P4322 [JSOI2016]最佳团体 (分数规划)

题目链接:https://www.luogu.com.cn/problem/P4322

分数规划
二分后直接树上依赖背包
树上依赖背包的写法

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;

const int maxn = 2505;
const double eps = 1e-4;

int n,k;
double x;
double s[maxn],p[maxn];
double f[maxn][maxn];

int h[maxn],cnt = 0;
struct E{
	int to,next;
}e[maxn];
inline void add(int u,int v){
	e[++cnt].to = v;
	e[cnt].next = h[u];
	h[u] = cnt;
}

int sz[maxn];

inline void dfs(int u,int par){
	sz[u] = 1;
	f[u][0] = 0;
	f[u][1] = p[u] - x * s[u];
	
	for(register int i=h[u];i;i=e[i].next){
		int v=e[i].to;

		dfs(v,u);
		sz[u] += sz[v];
		for(register int j=sz[u];j>=2;--j){
			for(register int k=0;k<=sz[v] && k<j ;++k){
				f[u][j] = max(f[u][j],f[u][j-k] + f[v][k]);
			}
		}	
	}
}

inline bool check(double mid){
	x = mid;
	memset(f,-63,sizeof(f));
	dfs(1,0);
	
	return (f[1][k] >= 0);
}

ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }

int main(){
	k = read(), n = read();
	++k; ++n; int u;
	for(int i=2;i<=n;++i){
		s[i] = read(), p[i] = read(), u = read() + 1;
		add(u,i);
	}
	
	double l = 0, r = 10000; double mid;
	while(r - l >= eps){
		mid = (l+r) / 2.0;
		if(check(mid)){
			l = mid;
		}else{
			r = mid;
		}
	}
	
	printf("%.3lf\n",l);
	
	return 0;
}
posted @ 2020-10-27 00:34  Tartarus_li  阅读(64)  评论(0编辑  收藏  举报