zoukankan      html  css  js  c++  java
  • bzoj4753 最佳团体

    题目描述

    JSOI 信息学代表队一共有 NN 名候选人,这些候选人从 11 到 NN 编号。方便起见,JYY 的编号是 00 号。每个候选人都由一位编号比他小的候选人R_iRi 推荐。如果 R_i = 0Ri=0​,则说明这个候选人是 JYY 自己看上的。

    为了保证团队的和谐,JYY 需要保证,如果招募了候选人 ii,那么候选人 R_iRi 也一定需要在团队中。当然了,JYY 自己总是在团队里的。每一个候选人都有一个战斗值 P_iPi ,也有一个招募费用 S_iSi 。JYY 希望招募 KK 个候选人(JYY 自己不算),组成一个性价比最高的团队。也就是,这 KK 个被 JYY 选择的候选人的总战斗值与总招募费用的比值最大。

    输入输出格式

    输入格式:

    输入一行包含两个正整数 KK 和 NN 。

    接下来 NN 行,其中第 ii 行包含三个整数 S_iSi , P_iPi , R_iRi , 表示候选人 ii 的招募费用,战斗值和推荐人编号。

    输出格式:

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

    这题涉及到了比值最大,最好用分数规划来解决。

    我们需要求出pi和ri的比值最大,不妨设Σpi/Σri>=x  ,经过转移Σpi>=Σri*x => Σpi-Σri*x>=0. 由此可见,我们可以二分出来一个x使这个值>=0.

    然后我们可以用树形DP来计算出最优值。

    我们先DFS一遍得到每个树上节点的DFS序(时间戳),令f[i][j]为DFS序为i的点,取j个的最优值。

    如果当前点取,说明自己的子树也可以取,所以f[i+1][j+1]=max(f[i+1][j+1],f[i][j]+val[i]);

    如果当前点不取,说明要取到下一颗树,我们记录size[i]代表以i为根的子树的大小。根据DFS序的性质,我们知道下一颗和自己平行的子树的DFS序为i+size.

    所以转移方程是:f[i+size[i]][j]=max(f[i+size[i]][j],f[i][j]);

    // luogu-judger-enable-o2
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    #include <cstring>
    #include <stack>
    #define in(a) a=read()
    #define MAXN 200020
    #define REP(i,k,n) for(int i=k;i<=n;i++)
    using namespace std;
    inline int read(){
        int x=0,f=1;
        char ch=getchar();
        for(;!isdigit(ch);ch=getchar())
            if(ch=='-')
                f=-1;
        for(;isdigit(ch);ch=getchar())
            x=x*10+ch-'0';
        return x*f;
    }
    int k,n;
    int INF=99999999;
    double p[2510],s[2510];
    int total=0,to[2520],nxt[2510],head[2510];
    int cnt=0,dfn[2510],ind[2510],size[2510];
    double f[2510][2510],val[2510];
    inline void adl(int a,int b){
        total++;
        to[total]=b;
        nxt[total]=head[a];
        head[a]=total;
        return ;
    }
    inline void DFS(int u){
        dfn[u]=cnt;
        ind[cnt++]=u;
        size[u]=1;
        for(int e=head[u];e;e=nxt[e]){
            DFS(to[e]);
            size[u]+=size[to[e]];
        }
        return ;
    }
    inline double DP(double x){
        //cout<<x<<endl;
        REP(i,1,n){
            val[i]=p[ind[i]]-x*s[ind[i]];
            //cout<<ind[i]<<" "<<val[i]<<endl;
        }
        REP(i,1,n+1)
            REP(j,0,k+1)
                f[i][j]=-INF;
        REP(i,0,n)
            REP(j,0,min(i,k+1)){
                f[i+1][j+1]=max(f[i+1][j+1],f[i][j]+val[i]);
                f[i+size[ind[i]]][j]=max(f[i+size[ind[i]]][j],f[i][j]);
            }
        /*REP(i,0,n){
            REP(j,0,min(i,k+1))
                cout<<f[i][j]<<" ";
            cout<<endl;
        }*/
        return f[n+1][k+1];
    }
    int main(){
        in(k);in(n);
        int a;
        double maxn=-INF;
        REP(i,1,n){
            scanf("%lf%lf%d",&s[i],&p[i],&a);
            adl(a,i);
            maxn=max(maxn,p[i]);
        }
        DFS(0);
        val[0]=0.0;
        double left=0.0,right=maxn;
        while(right-left>0.00001){
            double mid=(left+right)/2.0;
            //cout<<left<<" "<<right<<" "<<mid<<endl;
            if(DP(mid)>=0.00001)  left=mid;
            else  right=mid;
        }
        printf("%.3lf",left);
        return 0;
    }
    /*
    2 4
    1 2 0
    2 2 0
    1 3 1
    2 3 1
    */

     

  • 相关阅读:
    HTML5 拖放(Drag 和 Drop)详解与实例
    JS中的六大数据类型
    关于创建本地docker仓库
    关于使用国内dock仓库,网易、DaoCloud
    关于Docker开通远程访问端口2375
    多个消费者监听同一个队列
    SQLite -附加数据库
    解密JDK8 枚举
    LoraLU
    深入理解display属性
  • 原文地址:https://www.cnblogs.com/jason2003/p/9737461.html
Copyright © 2011-2022 走看看