poj 2976 Dropping tests (二分搜索之最大化平均值之01分数规划)
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 tests with scores of /, /, and /. 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, ≤ n ≤ and ≤ k < n. The second line contains nintegers indicating ai for all i. The third line contains n positive integers indicating bi for all i. It is guaranteed that ≤ ai ≤ bi ≤ , , , . The end-of-file is marked by a test case with n = k = 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
Sample Output
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).
Source
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<stdlib.h>
using namespace std;
#define N 1006
int n,k;
double ratio;
struct Node{
double a,b;
bool friend operator <(Node x,Node y){
return x.a-ratio*x.b>y.a-ratio*y.b;
}
}node[N];
bool solve(double mid){
ratio=mid;
sort(node,node+n);
double sum1=;
double sum2=;
for(int i=;i<n-k;i++){
sum1+=node[i].a;
sum2+=node[i].b;
}
return sum1/sum2>=mid;
} int main()
{
while(scanf("%d%d",&n,&k)== && n+k!=){
for(int i=;i<n;i++){
scanf("%lf",&node[i].a);
}
for(int i=;i<n;i++){
scanf("%lf",&node[i].b);
}
double low=;
double high=;
for(int i=;i<;i++){
double mid=(low+high)/;
if(solve(mid)){
low=mid;
}
else{
high=mid;
}
}
printf("%.0lf\n",high*);
}
return ;
}
乍看以为贪心或dp能解决,后来发现贪心策略与当前的总体准确率有关,行不通,于是二分解决。
依然需要确定一个贪心策略,每次贪心地去掉那些对正确率贡献小的考试。如何确定某个考试[a_i, b_i]对总体准确率x的贡献呢?a_i / b_i肯定是不行的,不然例子里的[0,1]会首当其冲被刷掉。在当前准确率为x的情况下,这场考试“额外”对的题目数量是a_i – x * b_i,当然这个值有正有负,恰好可以作为“贡献度”的测量。于是利用这个给考试排个降序,后k个刷掉就行了。
之后就是二分搜索了,从0到1之间搜一遍,我下面的注释应该很详细,不啰嗦了。
#ifndef ONLINE_JUDGE
#pragma warning(disable : 4996)
#endif
#include <iostream>
#include <algorithm>
#include <cmath>
#include <iomanip>
using namespace std; #define MAX_N 1000
int n, k;
double x; // 搜索过程中的正确率
struct Test
{
int a, b;
bool operator < (const Test& other) const
{
return a - x * b > other.a - x * other.b; // 按照对准确率的贡献从大到小排序
}
};
Test test[MAX_N]; // 判断是否能够获得大于mid的准确率
bool C(double mid)
{
x = mid;
sort(test, test + n);
double total_a = , total_b = ;
for (int i = ; i < n - k; ++i) // 去掉后k个数计算准确率
{
total_a += test[i].a;
total_b += test[i].b;
} return total_a / total_b > mid;
} ///////////////////////////SubMain//////////////////////////////////
int main(int argc, char *argv[])
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
while (cin >> n >> k && (n || k))
{
for (int i = ; i < n; ++i)
{
cin >> test[i].a;
}
for (int i = ; i < n; ++i)
{
cin >> test[i].b;
} double lb = ; double ub = ;
while (abs(ub - lb) > 1e-)
{
double mid = (lb + ub) / ;
if (C(mid))
{
lb = mid; // 行,说明mid太小
}
else
{
ub = mid; // 不行,说明mid太大
}
} cout << fixed << setprecision() << lb * << endl;
}
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
system("out.txt");
#endif
return ;
}
///////////////////////////End Sub//////////////////////////////////
poj 2976 Dropping tests (二分搜索之最大化平均值之01分数规划)的更多相关文章
- poj 3111 K Best (二分搜索之最大化平均值之01分数规划)
		
Description Demy has n jewels. Each of her jewels has some value vi and weight wi. Since her husband ...
 - POJ 2976 Dropping tests【二分 最大化平均值】
		
题意:定义最大平均分为 (a1+a2+a3+---+an)/(b1+b2+---+bn),求任意去除k场考试的最大平均成绩 和挑战程序设计上面的最大化平均值的例子一样 判断是否存在x满足条件 (a1+ ...
 - poj    2976    Dropping tests  二分搜索+精度处理
		
Dropping tests Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8349 Accepted: 2919 De ...
 - NYOJ 914 Yougth的最大化【二分/最大化平均值模板/01分数规划】
		
914-Yougth的最大化 内存限制:64MB 时间限制:1000ms 特判: No 通过数:3 提交数:4 难度:4 题目描述: Yougth现在有n个物品的重量和价值分别是Wi和Vi,你能帮他从 ...
 - 二分算法的应用——最大化平均值 POJ 2976 Dropping tests
		
最大化平均值 有n个物品的重量和价值分别wi 和 vi.从中选出 k 个物品使得 单位重量 的价值最大. 限制条件: <= k <= n <= ^ <= w_i <= v ...
 - POJ - 2976 Dropping tests && 0/1 分数规划
		
POJ - 2976 Dropping tests 你有 \(n\) 次考试成绩, 定义考试平均成绩为 \[\frac{\sum_{i = 1}^{n} a_{i}}{\sum_{i = 1}^{n} ...
 - POJ - 2976 Dropping tests(01分数规划---二分(最大化平均值))
		
题意:有n组ai和bi,要求去掉k组,使下式值最大. 分析: 1.此题是典型的01分数规划. 01分数规划:给定两个数组,a[i]表示选取i的可以得到的价值,b[i]表示选取i的代价.x[i]=1代表 ...
 - POJ 2976 Dropping tests 【01分数规划+二分】
		
题目链接:http://poj.org/problem?id=2976 Dropping tests Time Limit: 1000MS Memory Limit: 65536K Total S ...
 - POJ 2976 Dropping tests(01分数规划入门)
		
Dropping tests Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11367 Accepted: 3962 D ...
 
随机推荐
- 《Java虚拟机原理图解》1.4 class文件里的字段表集合--field字段在class文件里是如何组织的
			
0.前言 了解JVM虚拟机原理是每个Java程序猿修炼的必经之路.可是因为JVM虚拟机中有非常多的东西讲述的比較宽泛.在当前接触到的关于JVM虚拟机原理的教程或者博客中,绝大部分都是充斥的文字性的描写 ...
 - springMVC 注解版
			
http://blog.csdn.net/liuxiit/article/details/5756115 http://blog.csdn.net/hantiannan/article/categor ...
 - linux增大交换分区
			
进来在批量搭建环境,遇到搭建完环境之后发现swap忘记的情况,后来百度了下,发现了下面的方法,网上可能存在好多相应的帖子说这个事情也比较简单,以下是自己实践的结果,分享给大家. 1.查看现有memor ...
 - XtraBackup做mysql主从同步
			
一.背景: 线上一个主库压力比较大,所以增加一个从库,但是不能重启或者停止主库的正常运行,不能锁库锁表影响业务的正常运行.所以这里想到了XtraBackup 二.XtraBackup介绍: Xtrab ...
 - Linux 数据 CD 刻录
			
http://www.cyberciti.biz/tips/linux-burning-multi-session-cds-on-linux.html #mkisofs -dvd-video -inp ...
 - HTML 转文本及HTML内容提取(C#)
			
//1.HTML直接转文本 //使用方法 HtmlToText convert = new HtmlToText(); textBox2.Text = convert.Convert(textBox1 ...
 - linux 定时执行shell脚本
			
转自:http://blog.csdn.net/jingxiangren/article/details/4745631 在oracle 中可以利用dbms_job包定时执行pl/sql.sql过程, ...
 - debug 心得
			
前天做了一个题,就是个简单的状压记忆化搜索,但是debuge了俩小时,给我整的快吐血了,各种不可思议的错误,我都要怀疑是不是电脑有毛病了,后来发现数组开小了,看来以后遇到不可思议的错误就要检查数组开没 ...
 - 1.1C++入门  未完待续。。。
			
第一个C++程序: #include<iostream> int main() { std::cout << "Hello World !" << ...
 - css3之background
			
background background: (1)url(image1.png) right bottom, (2)url(image2.png) center, (3)url(image3.png ...