Dropping tests
 
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 6373   Accepted: 2198

【Description】

In a certain course, you take n tests. If you get ai out of bi questions correct on test i, your cumulative average is defined to be

.

Given your test scores and a positive integer k, determine how high you can make your cumulative average if you are allowed to drop any k of your test scores.

Suppose you take 3 tests with scores of 5/5, 0/1, and 2/6. Without dropping any tests, your cumulative average is . However, if you drop the third test, your cumulative average becomes .

【Input】

The input test file will contain multiple test cases, each containing exactly three lines. The first line contains two integers, 1 ≤ n ≤ 1000 and 0 ≤ k < n. The second line contains n integers indicating ai  for all i. The third line contains n positive integers indicating bi for all i. It is guaranteed that 0 ≤ aibi ≤ 1, 000, 000, 000. The end-of-file is marked by a test case with n = k = 0 and should not be processed.

【Output】

For each test case, write a single line with the highest cumulative average possible after dropping k of the given test scores. The average should be rounded to the nearest integer.

【Sample Input】

3 1
5 0 2
5 1 6
4 2
1 2 7 9
5 6 7 9
0 0

【Sample Output】

83
100

【Hint】

To avoid ambiguities due to rounding errors, the judge tests have been constructed so that all answers are at least 0.001 away from a decision boundary (i.e., you can assume that the average is never 83.4997).

【算法分析】

所谓的01分数规划问题就是指这样的一类问题,给定两个数组,a[i]表示选取i的收益,b[i]表示选取i的代价。如果选取i,定义x[i]=1,否则x[i]=0。

每一个物品只有选或者不选两种方案,求一个选择方案即从其中选取k组a[i]/b[i],使得R=sigma(a[i]*x[i])/sigma(b[i]*x[i])取得最值,即所有选择物品的总收益/总代价的值最大或是最小。

01分数规划问题主要包含一般的01分数规划、最优比率生成树问题、最优比率环问题等。

来看目标式:

R=sigma(a[i]*x[i])/sigma(b[i]*x[i])

我们的目标是使得R达到最大或者最小,首先定义一个函数

F(L)=sigma(a[i]*x[i])-L*sigma(b[i]*x[i]),显然这只是对目标式的一个简单的变形。

分离参数,得到F(L):=sigma((a[i]-L*b[i])*x[i]),记d[i]=a[i]-L*b[i],那么F(L):=sigma(d[i]*x[i])。

接下来重点注意一下d[i]和F(L)的单调性。

如果我们已知了L,则所有的的d[i]是已知的,那么这里的贪心策略是为了得到一个最优的F(L),我们只需要将d[i]排序之后取其中的前k个或者后k个。也就是说,给定L,我们可以直接求出对应的F(L)。

接下来是F(L),因为b[i]是正的,显然F(L)对于L是单调递减的,这就启发我们可以通过某种方法把F(L)逼近至0,当F(L)=0时,即 sigma(a[i]*x[i])-L*sigma(b[i]*x[i])=0,那么此时的L就是最优值。

然后还要注意到的问题是,我们每次贪心地取d[i]中最小的k个,则最终使得F(L)趋于0的L会是最小的比值;如果每次贪心地取d[i]中最大的k个,则最终使得F(L)趋于0的L会是最大的比值。

考虑F(L):=sigma((a[i]-L*b[i])*x[i])式中,我们取了最后k个di[i]使得F(L)=0,则如果用此时的L去取全部的数,F(L)_tot将是小于零的,也即使得整个F(L)_tot趋于0的L_tot是小于L的。故L是取K组数的情况下,最大的比值。(这段说的有点绕口)

另外再注意到的一点是,如果将a[i]与b[i]上下颠倒,求解的方法相同,结果跟颠倒前也是刚好相对应的。

最后又想到了一个关键点,k的值对最后的结果会是什么影响:

贪心地说,为了使结果尽可能的大,k也要尽可能的大,即尽可能多的舍弃一些,剩下选取的数越少,均值越大

总结F(L)的两个重要性质如下就是:

 1.  F(L)单调递减

 2.  F(max(L)/min(L)) = 0

之后的逼近方法可以有两种选择

1.二分法

二分区间,不断把F(L)逼近至0,若F(L)<0说明L过大,若F(L)>0说明L过小,直到逼近得到一个最优的L;

 /* ***********************************************
MYID : Chen Fan
LANG : G++
PROG : PKU_2976_Erfen
************************************************ */ #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm> #define eps 1e-6 using namespace std; typedef struct nod
{
int a,b;
double r;
} node; bool op(node a,node b)
{
return a.r>b.r;
} node p[]; int main()
{
freopen("2976.txt","r",stdin); int n,k; while(scanf("%d%d",&n,&k))
{
if (n==&&k==) break; for (int i=;i<=n;i++) scanf("%d",&p[i].a);
for (int i=;i<=n;i++) scanf("%d",&p[i].b); int m=n-k;
double left=,right=;
while (left+eps<right)
{
double mid=(left+right)/;
for (int i=;i<=n;i++) p[i].r=p[i].a-mid*p[i].b;
sort(&p[],&p[n+],op);
double temp=;
for (int i=;i<=m;i++) temp+=p[i].r;
if (temp>) left=mid;
else right=mid;
} printf("%.0f\n",left*);
} return ;
}

2.Dinkelbach

从另外一个角度考虑,每次给定一个L,除了我们用来判定的F(L)之外,我们可以通过重新计算得到一个L',而且能够证明L'一定是更接近最优解的,那么我们可以考虑直接把L移动到L'上去。当L=L'时,说明已经没有更接近最优的解了,则此时的L就是最优解。

注意在Dinkelbach算法中,F(L)仍然是判定是否更接近最优解的工具,也即此时d[i]的选择仍然与之前相同,只是最后移动解的时候是把L直接移往L'

 /* ***********************************************
MYID : Chen Fan
LANG : G++
PROG : PKU_2976_Dinkelbach
************************************************ */ #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath> #define eps 1e-6 using namespace std; typedef struct nod
{
int a,b,index;
double r;
} node; bool op(node a,node b)
{
return a.r>b.r;
} node p[]; int main()
{
freopen("2976.txt","r",stdin); int n,k; while(scanf("%d%d",&n,&k))
{
if (n==&&k==) break; for (int i=;i<=n;i++) scanf("%d",&p[i].a);
for (int i=;i<=n;i++) scanf("%d",&p[i].b); int m=n-k;
double l=,temp=;
while (fabs(l-temp)>=eps)
{
l=temp;
for (int i=;i<=n;i++) p[i].r=p[i].a-l*p[i].b;
sort(&p[],&p[n+],op);
int x=,y=;
for (int i=;i<=m;i++)
{
x+=p[i].a;
y+=p[i].b;
}
temp=(double)x/y;
} printf("%.0f\n",temp*);
} return ;
}

POJ 2976 Dropping tests 01分数规划 模板的更多相关文章

  1. POJ 2976 Dropping tests 01分数规划

    给出n(n<=1000)个考试的成绩ai和满分bi,要求去掉k个考试成绩,使得剩下的∑ai/∑bi*100最大并输出. 典型的01分数规划 要使∑ai/∑bi最大,不妨设ans=∑ai/∑bi, ...

  2. $POJ$2976 $Dropping\ tests$ 01分数规划+贪心

    正解:01分数规划 解题报告: 传送门! 板子题鸭,,, 显然考虑变成$a[i]-mid\cdot b[i]$,显然无脑贪心下得选出最大的$k$个然后判断是否大于0就好(,,,这么弱智真的算贪心嘛$T ...

  3. POJ - 2976 Dropping tests(01分数规划---二分(最大化平均值))

    题意:有n组ai和bi,要求去掉k组,使下式值最大. 分析: 1.此题是典型的01分数规划. 01分数规划:给定两个数组,a[i]表示选取i的可以得到的价值,b[i]表示选取i的代价.x[i]=1代表 ...

  4. POJ 2976 Dropping tests(分数规划)

    http://poj.org/problem?id=2976 题意: 给出ai和bi,ai和bi是一一配对的,现在可以删除k对,使得的值最大. 思路: 分数规划题,可以参考<挑战程序竞赛> ...

  5. [poj 2976] Dropping tests (分数规划 二分)

    原题: 传送门 题意: 给出n个a和b,让选出n-k个使得(sigma a[i])/(sigma b[i])最大 直接用分数规划.. code: //By Menteur_Hxy #include & ...

  6. Dropping tests(01分数规划)

    Dropping tests Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8176   Accepted: 2862 De ...

  7. [poj2976]Dropping tests(01分数规划,转化为二分解决或Dinkelbach算法)

    题意:有n场考试,给出每场答对的题数a和这场一共有几道题b,求去掉k场考试后,公式.的最大值 解题关键:01分数规划,double类型二分的写法(poj崩溃,未提交) 或者r-l<=1e-3(右 ...

  8. POJ2976 Dropping tests —— 01分数规划 二分法

    题目链接:http://poj.org/problem?id=2976 Dropping tests Time Limit: 1000MS   Memory Limit: 65536K Total S ...

  9. poj Dropping tests 01分数规划---Dinkelbach算法

    果然比二分要快将近一倍.63MS.二分94MS. #include <iostream> #include <algorithm> #include <cstdio> ...

随机推荐

  1. c#抓取网页内容乱码的解决方案

    写过爬虫的同学都知道,这是个很常见的问题了,一般处理思路是: 使用HttpWebRequest发送请求,HttpWebResponse来接收,判断HttpWebResponse中”Content-Ty ...

  2. 8.5 sikuli 集成进eclipse 报错:can't be found on the disk

    运行提示can't be found on the disk

  3. 多线程junit单元测试

    junit中测试完成后会进行jvm退出,而不是线程退出,所以任一线程退出都会导致测试结束,junit想进行多线程测试需要进行另外包装,网上看到一个投机取巧的例子还不错,贴上我的测试代码(代码中我需要测 ...

  4. xv6的设计trick(不断更新)

    1.每个进程通过时钟中断出发trap.c中的 if(proc && proc->state == RUNNING && tf->trapno == T_IR ...

  5. HDU2066一个人的旅行/最短路问题

    一个人的旅行 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Subm ...

  6. 最小点集覆盖=最大匹配<二分图>/证明

    来源 最小点集覆盖==最大匹配. 首先,最小点集覆盖一定>=最大匹配,因为假设最大匹配为n,那么我们就得到了n条互不相邻的边,光覆盖这些边就要用到n个点. 现在我们来思考为什么最小点击覆盖一定& ...

  7. php 四种基础的算法 ---- 冒泡排序法

    1. 冒泡排序法  *     思路分析:法如其名,就是像冒泡一样,每次从数组当中 冒一个最大的数出来.  *     比如:2,4,1    // 第一次 冒出的泡是4  *             ...

  8. 初探JavaScript魅力(五)

    JS简易日历    innerHTML <title>无标题文档</title> <script> var neirong=['一','二','三','四','五' ...

  9. hdu1426 Sudoku Killer

    Sudoku Killer Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Total ...

  10. Landsat TM DN值转为表观反射率

    日地距离计算参见<中华人民共和国气象行业标准太阳能资源评估方法>