zoukankan      html  css  js  c++  java
  • [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
    ",ans);
    	return 0;
    }
    



  • 相关阅读:
    Interview with BOA
    Java Main Differences between HashMap HashTable and ConcurrentHashMap
    Java Main Differences between Java and C++
    LeetCode 33. Search in Rotated Sorted Array
    LeetCode 154. Find Minimum in Rotated Sorted Array II
    LeetCode 153. Find Minimum in Rotated Sorted Array
    LeetCode 75. Sort Colors
    LeetCode 31. Next Permutation
    LeetCode 60. Permutation Sequence
    LeetCode 216. Combination Sum III
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9136032.html
Copyright © 2011-2022 走看看