牛客多校 gpa(01分数规划)

链接:https://www.nowcoder.com/acm/contest/143/A
来源:牛客网
 

题目描述

Kanade selected n courses in the university. The academic credit of the i-th course is s[i] and the score of the i-th course is c[i].

At the university where she attended, the final score of her is 

Now she can delete at most k courses and she want to know what the highest final score that can get.

输入描述:

The first line has two positive integers n,k

The second line has n positive integers s[i]

The third line has n positive integers c[i]

输出描述:

Output the highest final score, your answer is correct if and only if the absolute error with the standard answer is no more than 10-5

示例1

输入

复制

3 1
1 2 3
3 2 1

输出

复制

2.33333333333

说明

Delete the third course and the final score is 

备注:

1≤ n≤ 105

0≤ k < n

1≤ s[i],c[i] ≤ 103

先举一个栗子

给定两个数组,a[i]表示选取i的收益,b[i]表示选取i的代价。如果选取i,定义x[i]=1否则x[i]=0。每一个物品只有选或者不选两种方案,求一个选择方案使得R=sigma(a[i]*x[i])/sigma(b[i]*x[i])取得最值,即所有选择物品的总收益/总代价的值最大或是最小。

之后我们设L=R,则有F(L)=sigma(a[i]*x[i])-L*sigma(b[i]*x[i])

                                          =sigma((a[i]-L*b[i])*x[i]

之后记做d[i]=a[i]-L*b[i]

则 F(L)=sigma(d[i])

若F(L)>0 ,则有sigma(a[i]*x[i])/sigma(b[i]*x[i])>R,即有更优解

F(L)<0时没有意义,因为取不到F(L)这个值

F(L)=0即为最优解

同时可知d[i]是单调递减(因为是一元一次方程)

所以通过二分可以找到最优解

——————————————我是分割线——————————————————————————

那么这道题同理,思想相同

R=sigma(s[i]*c[i])/sigma(s[i])

F(L)=sigma(s[i]*c[i])-L*sigma(s[i])

      =sigma((c[i]-L)*s[i])

因为F(L)=sigma(d[i])且F(L)=0为最优解

所以计算d[i]并且排序,因为删除k个,并且要保证F(L)越大越好,因为越大越有机会大于0,大于0就可以进一步寻找最优解,所以之后从k开始遍历到最后(数组以0开始)

以下是代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define require 1e-6
double c[100005],s[100005];
double d[100005];
int main()
{
    int num,k;
    memset(c,0,sizeof(c));
    memset(s,0,sizeof(s));
    scanf("%d%d",&num,&k);
    for(int i=0;i<num;i++)
        scanf("%lf",&s[i]);
    double maxn=0;
    for(int i=0;i<num;i++){
        scanf("%lf",&c[i]);
        maxn=max(maxn,c[i]);
    }
    double l=0,r=maxn;
    while(r-l>require){
        memset(d,0,sizeof(d));
        double mid=(l+r)/2;
        for(int i=0;i<num;i++)
            d[i]=(c[i]-mid)*s[i];
        sort(d,d+num);
        double sum=0;
        for(int i=k;i<num;i++){
            sum+=d[i];
        }
        if(sum>=0)
            l=mid;
        else
            r=mid;
    }
    printf("%.6lf\n",l);
}

其中第一段证明参考大佬博客http://www.cnblogs.com/perseawe/archive/2012/05/03/01fsgh.html

后来按照自己的思路写了出来,如有错误之处欢迎指出(~ ̄▽ ̄)~ 

猜你喜欢

转载自blog.csdn.net/qq_41548233/article/details/81381970