[bzoj4753][Jsoi2016]最佳团体【0/1分数规划】【dp】

【题目描述】

Description

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

Input

输入一行包含两个正整数K和N。
接下来N行,其中第i行包含3个整数Si,Pi,Ri表示候选人i的招募费用,战斗值和推荐人编号。
对于100%的数据满足1≤K≤N≤2500,0<"Si,Pi"≤10^4,0≤Ri<i

Output

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

Sample Input

1 2
1000 1 0
1 1000 1

Sample Output

0.001

HINT

2017.9.12新加数据一组 By GXZlegend

Source

【题解】

 题目大意是一棵树,每个点有价值和花费,要选择一个包含根节点的连通块,使 价值和A/花费和B 最大。

0/1分数规划套路题,变式得 A=ans*B,显然可以二分ans,将每个的权值设为a-ans*b,再在新树上判断是否有可行的连通块使权值和 >0,dp一下就行了

若存在,则说明当前二分的ans可以被满足,否则不行。

/* --------------
    user Vanisher
    problem bzoj-4753 
----------------*/
# include <bits/stdc++.h>
# define 	ll 		long long
# define 	inf 	1e9
# define 	eps 	1e-6
# define 	N 		3010
using namespace std;
int read(){
	int tmp=0, fh=1; char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
	while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
	return tmp*fh;
}
struct node{
	int data,next;
}e[N];
int place,head[N],size[N],k,n,fa[N];
double a[N],b[N],f[N][N],g[N];
void build(int u, int v){
	e[++place].data=v; e[place].next=head[u]; head[u]=place;
}
void dp(int x, double p){
	size[x]=1; f[x][0]=0, f[x][1]=a[x]-p*b[x];
	for (int ed=head[x]; ed!=0; ed=e[ed].next){
		dp(e[ed].data,p);
		for (int i=0; i<=size[x]+size[e[ed].data]; i++) g[i]=-inf;
		g[0]=0;
		for (int i=1; i<=size[x]; i++)
			for (int j=0; j<=size[e[ed].data]; j++)
				g[i+j]=max(g[i+j],f[e[ed].data][j]+f[x][i]);
		size[x]=size[x]+size[e[ed].data];
		for (int i=0; i<=size[x]; i++)
			f[x][i]=g[i];
	}
}
double check(double p){
	dp(1,p);
	return f[1][k];
}
int main(){
	k=read()+1, n=read()+1;
	for (int i=2; i<=n; i++){
		b[i]=read(), a[i]=read(), fa[i]=read()+1;
		build(fa[i],i);
	}
	double pl=0, pr=2e4, ans=0;
	while (pl+eps<=pr){
		double mid=(pl+pr)/2;
		if (check(mid)>=0)
			ans=mid, pl=mid+eps;
			else pr=mid-eps;
	}
	printf("%.3lf\n",ans);
	return 0;
}



posted @ 2018-01-27 10:32  Vanisher  阅读(114)  评论(0编辑  收藏  举报