/*
translation:
给出n场考试,每场考试有总题量,和你答对的题量。现在要求你去掉一些考试项目,使得你的正确率能够达到最大是多少?
solution:
0/1分数规划,二分解决
赤裸裸的0/1分数规划,但是此题不能采用dp,因为a,b数据太大,超时。所以考虑采用二分来枚举可能的最大正确率。
然后判断该次枚举的是否可能。这样就转化成了二分确定最大值的问题。现在怎么判断是个问题。因为不能直接用贪心法来
根据单次考试的正确率来决策。这样样例中的0/1项在第一次就被筛了。因为总的正确率是根据总的题量和总的答对数来计算的
单单根据一次考试是无法得到正确结果。所以考虑有一子集使得能够满足枚举的正确率mid。这样有sum(ai)/sum(bi) >= mid
简单变换之后:sum(ai - mid * bi) >= 0。这样对每场考试就能产生一个衡量指标 ai - mid * bi。问题进一步转换成
在众多考试项目中选择一个n-k子集,使得它们的衡量指标之和大于等于0.所以只要排序一下,然后从下标k开始知道末尾,相加起来的
就是所能选出的最大衡量指标。这样就能进行判断了。
note:
*:0/1分数规划的二分做法
*:注意输出离小数最近的一个整数的做法。
date:
2016.11.3
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 1000 + 10;
struct Test
{
int a, b;
} t[maxn];
int n, k, sum_up, sum_down;
double s[maxn];
bool check(double mid)
{
for(int i = 0; i < n; i++)
s[i] = (double)t[i].a - mid * t[i].b;
sort(s, s + n);
double res = 0.0;
for(int i = k; i < n; i++) res += s[i];
return res >= 0;
}
int main()
{
//freopen("in.txt", "r", stdin);
while(~scanf("%d%d", &n, &k)){
if(!n && !k) break;
sum_up = sum_down = 0;
for(int i = 0; i < n; i++) scanf("%d", &t[i].a);
for(int i = 0; i < n; i++) scanf("%d", &t[i].b);
double pl = 0.0, pr = 1.0;
for(int i = 0; i < 100; i++){
double mid = (pl + pr) / 2.0;
if(check(mid)) pl = mid;
else pr = mid;
}
printf("%d\n", (int)(pr*100 + 0.5));
}
return 0;
}
poj2976(二分求解0/1分数规划模型)
最新推荐文章于 2022-06-26 18:57:24 发布