zoukankan      html  css  js  c++  java
  • BZOJ_4753_[Jsoi2016]最佳团体_树形背包+01分数规划

    BZOJ_4753_[Jsoi2016]最佳团体_树形背包+01分数规划

    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


    二分答案x,令t[i]=P[i]-x*S[i]。

    然后建立源点S,跑个树形背包求f[S][K+1]是否大于0即可。

    按子树合并的树形背包复杂度是$O(n^2)$的。

    代码:

    #include <cstdio>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    typedef double f2;
    #define N 2550
    #define S (n+1)
    #define eps 1e-6
    #define inf 1000000000
    int head[N],to[N<<1],nxt[N<<1],cnt,n,K,A[N],B[N],C[N],siz[N];
    f2 t[N],g[N],f[N][N];
    inline void add(int u,int v) {
    	to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
    }
    void dfs(int x) {
    	siz[x]=1;int i,j,k; f[x][1]=t[x];
    	for(k=head[x];k;k=nxt[k]) {
    		dfs(to[k]);
    		for(i=1;i<=siz[x]+siz[to[k]];i++) g[i]=f[x][i];
    		for(i=1;i<=siz[x];i++) if(f[x][i]>-inf) {
    			for(j=1;j<=siz[to[k]];j++) if(f[to[k]][j]>-inf) {
    				g[i+j]=max(g[i+j],f[x][i]+f[to[k]][j]);
    			}
    		}
    		for(i=1;i<=siz[x]+siz[to[k]];i++) f[x][i]=g[i];
    		siz[x]+=siz[to[k]];
    	}
    }
    bool check(f2 x) {
    	int i,j;
    	for(i=0;i<=n;i++) t[i]=B[i]-x*A[i];
    	t[S]=0;
    	for(i=1;i<=S;i++) {
    		for(j=1;j<=K+1;j++) {
    			f[i][j]=-inf;
    		}
    	}
    	dfs(S);
    	return f[S][K+1]>eps;
    }
    int main() {
    	//freopen("sales.in","r",stdin);
    	//freopen("sales.out","w",stdout);
    	scanf("%d%d",&K,&n);
    	int i;
    	f2 sum=0;
    	for(i=1;i<=n;i++) {
    		scanf("%d%d%d",&A[i],&B[i],&C[i]);
    		if(!C[i]) C[i]=S;
    		add(C[i],i); sum+=A[i];
    	}
    	f2 l=0,r=10000;
    	while(r-l>eps) {
    		f2 mid=(l+r)/2;
    		if(check(mid)) l=mid;
    		else r=mid;
    	}
    	printf("%.3f
    ",l);
    }
    
  • 相关阅读:
    对网络状态监控的两种方法,提示用户联网
    android基于PayPal实现移动在线付款
    android实现拍照,并将图片保存到SD下
    异步下载图片并对对图片进行压缩处理
    微软经典案例系列课程(视频课程讲师:杨丹)
    微软Silverlight开发团队零距离接触系列课程(视频课程讲师:徐鹏阳)
    SaaS软件即服务系列课程(视频课程讲师:吴淏)
    Mobile应用实例分析系列(视频课程讲师:刘彦博)
    模式与实践系列课程(视频课程讲师:张大磊)
    SQL Server 2005 BI综合案例系列课程(视频课程讲师:李苗/金立钢)
  • 原文地址:https://www.cnblogs.com/suika/p/9092743.html
Copyright © 2011-2022 走看看