zoukankan      html  css  js  c++  java
  • jzoj3454 表白(love)解题报告(01分数规划+DP)

    题目链接:https://jzoj.net/senior/#contest/show/2414/2

    题目描述:

    鸡腿是CZYZ的著名DS,但是不想追妹子的DS不是好GFS,所以鸡腿想通过表白来达到他追到妹子的目的!虽然你对鸡腿很无语,但是故事的设定是你帮助鸡腿找到了妹子,所以现在你必须帮助鸡腿安排表白来实现故事的结局 ! 


    鸡腿想到了一个很高(sha)明(bi)的做法,那就是去找人来组成表白队伍来增强气势 !鸡腿有很多好基友来帮忙,鸡腿数了数一共有N个人。但是鸡腿觉得大家排成两队来比较好看,而且鸡腿经过计算,第一队N1个人,第二队N2个人是最佳的队伍。问题来了...有些好基友们虽然很好心但是可能造成不好的影响(形象猥琐),所以鸡腿就给每个人打了分。Q1i表示第i个好基友排到第一队里时的好影响,C1i表示第i个好基友排到第一队里时的不良影响,Q2i表示第i个好基友排到第二队里时的好影响,C2i表示第i个好基友排到第二队里时的不良影响。请给鸡腿一种安排使得Q的和与C的和的比值最大,给出最大值。 

    Input

    第一行给出三个整数N、N1、N2。 

    第2到N+1行,每行四个整数Q1,C1,Q2,C2。 

    Output

    一行输出一个小数d表示最优化比例是d(保留6位小数) 

     

    Sample Input

    5 2 2
    12 5 8 3
    9 4 9 4
    7 3 16 6
    11 5 7 5
    18 10 6 3

    Sample Output

    2.444444

     

    样例分析就略过了,其实我自己也没有仔细分析

    下面直接开始讲题:

    这道题的含义很好理解,有两个队列,每个人有各自的属性,我们要做的就是最优化

    我们发现输出结果是个分数,考虑一下二分答案,发现若是答案t成立,则满足下面这个不等式:

    ∑(each k in Queue1)Q1k+∑(each k in Queue2)Q2k

    ----------------------------------------------------------- >=t

    ∑(each k in Queue1)C1k+∑(each k in Queue2)C2k

    移项之后可以得到:

    ∑(each k in Queue1)(Q1k-C1k*t) +∑(each k in Queue2)(Q2k-C2k*t)>=0

    于是这就是个01分数规划题

    问题转化为构造最大的∑(each k in Queue1)(Q1k-C1k*t) +∑(each k in Queue2)(Q2k-C2k*t),怎么做呢?我们采用DP的方法

    首先对于每一个人,我们计算出他的(q1i-c1i*t)-(q2i-c2i*t),注意中间是减号,为什么呢?我们考虑对最终答案的贡献,当然是越大越好,于是我们给这个新的属性(ne)从大到小排序

    队列1从前向后取,队列二从后向前取。比如我们考虑大于0的情况,我们认为它是“靠前的”,那么显然放在队列1里面是比放在队列2里面好的,放在队列2里面就是负数了嘛

    排序之后我们开始DP,用f[i][j] 表示前i 个人取了j 个进第一队的最大贡献,用g[i][j] 表示后i 个人取了j 个进第二队的最大贡献,最后用f[i][N1] +g[N-i][N2]来更新答案即可

    若是满足大于等于0的条件,就l=mid,不满足r=mid

    下面附上代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    const int inf=1e9+7;
    const int maxn=502;
    int n,n1,n2;
    double f[maxn][maxn],g[maxn][maxn];
    struct NODE
    {
        double q1,c1,q2,c2,ne;
    }m[maxn],k[maxn];
    bool cmp(NODE a,NODE b) {return a.ne>b.ne;}
    bool check(double t)
    {
        memset(f,-inf,sizeof(f));
        memset(g,-inf,sizeof(g));
        for (int i=1;i<=n;i++) k[i]=m[i];
        for (int i=1;i<=n;i++)
        k[i].ne=(k[i].q1-k[i].c1*t)-(k[i].q2-k[i].c2*t);
        sort(k+1,k+1+n,cmp);
        f[1][1]=k[1].q1-k[1].c1*t;
        f[1][0]=0;
        for (int i=2;i<=n;i++)
        for (int j=0;j<=min(i,n1);j++)
        {
            f[i][j]=f[i-1][j];
            f[i][j]=max(f[i][j],f[i-1][j-1]+k[i].q1-k[i].c1*t);
        }
        g[1][1]=k[n].q2-k[n].c2*t;
        g[1][0]=0;
        for (int i=2;i<=n;i++)
        for (int j=0;j<=min(i,n2);j++)
        {
            g[i][j]=g[i-1][j];
            g[i][j]=max(g[i][j],g[i-1][j-1]+k[n-i+1].q2-k[n-i+1].c2*t);
        }
        double ans=-1000;
        for (int i=1;i<=n;i++)
        if (i>=n1&&n-i>=n2) if (f[i][n1]+g[n-i][n2]>ans) ans=f[i][n1]+g[n-i][n2];
        if (ans>=0) return true;else return false;
    }
    int main()
    {
        //freopen("love.in","r",stdin);
        //freopen("love.out","w",stdout);
        scanf("%d%d%d",&n,&n1,&n2);
        for (int i=1;i<=n;i++)
        scanf("%lf%lf%lf%lf",&m[i].q1,&m[i].c1,&m[i].q2,&m[i].c2);
        double l=0,r=2000.0,mid;
        while (r-l>1e-12)
        {
            mid=(l+r)/2;
            if (check(mid)) l=mid;
            else r=mid;
        }
        printf("%.6f",mid);
        return 0;
    }
  • 相关阅读:
    JavaScript学习心得(六)
    JavaScript学习心得(五)
    JavaScript学习心得(四)
    JavaScript学习心得(三)
    JavaScript学习心得(二)
    JavaScript学习心得(一)
    socket异步接收信息
    DataTable将行转成列
    highcharts的柱状图边线
    w3cSchool jquery学习
  • 原文地址:https://www.cnblogs.com/xxzh/p/9274214.html
Copyright © 2011-2022 走看看