洛谷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;
}