Dropping tests [POJ2976] [01分数规划]

Description

今年有 n 场 ACM-ICPC 竞赛,小明每场都有资格参加。第 i 场竞赛共有 b[i] 道题。小明预测第 i场他能做出 a[i] 道题。为了让自己看着更“大佬”一些,小明想让自己平均做出的题数越大越好,也就是最大化大佬度,大佬度的定义如下:

为了达到这个目的,小明决定放弃 k 场比赛的参赛资格。请求出最大的大佬度。

例如有 3 场小型比赛,题数分别是 5 题、1 题、6 题,小明预测自己分别能做出 5 题、0题、2题。如果每场都参加,那么大佬度是 ,看着不怎么大佬。不过,如果放弃第 3 场比赛,那么大佬度就是 ,看着更加大佬了。

Input

输入测试文件含有多组测试,每组有 3 行。第一行有 2 个整数, 1 ≤ n ≤ 1000 和 0 ≤ k < n。第二行有 n 个整数,即每个 a[i]。第三行含有 n 个正整数 b[i]。保证 0 ≤ a[i] ≤ b[i] ≤ 1, 000, 000, 000。文件末尾由 n = k = 0 标识,并且不应该被处理。

Output

对于每组测试数据,输出一行整数,即放弃 k 场比赛后可能的最高大佬度。大佬度应该舍入到最近的整数。

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

Analysis

这是一个典型的01分数规划问题,什么意思?

在两个数列a,b中,选取部分出来,使得∑ai/∑bi最大

我们采用二分确定下届的方法,设∑ai/∑bi>=x

则∑(ai/(bi+x))>=0;

我们按贪心的方法,排序后选取n-m个出来,判断是否正确即可。

Code

 1 #include<set>
 2 #include<map>
 3 #include<queue>
 4 #include<stack>
 5 #include<cmath>
 6 #include<cstdio>
 7 #include<cstring>
 8 #include<iostream>
 9 #include<algorithm>
10 #define RG register ll
11 #define rep(i,a,b)    for(RG i=a;i<=b;++i)
12 #define per(i,a,b)    for(RG i=a;i>=b;--i)
13 #define ll long long
14 #define inf (1<<29)
15 #define maxn 1005
16 #define eps 1e-7
17 using namespace std;
18 ll n,m;
19 struct D{
20     double a,b;
21 }dat[maxn];
22 double tmp[maxn];
23 inline ll read()
24 {
25     ll x=0,f=1;char c=getchar();
26     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
27     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
28     return x*f;
29 }
30 
31 double DD;
32 
33 inline int cmp(const D &x,const D &y)
34 {
35     return x.a-x.b*DD>y.a-y.b*DD;    
36 }
37 
38 ll check(double lim)
39 {
40     DD=lim;
41     sort(dat+1,dat+1+n,cmp);
42     double sum=0;
43     rep(i,1,m)    sum+=dat[i].a-dat[i].b*lim;
44     return sum>=0;
45 }
46 
47 int main()
48 {
49     while(1)
50     {
51         double l=0,r=1,ans=0,mid;
52         n=read(),m=read();m=n-m;
53         if(!n&&!m)    return 0;
54         rep(i,1,n)    dat[i].a=read();
55         rep(i,1,n)    dat[i].b=read();
56         while(r-l>eps)
57         {
58             mid=(l+r)/2.0;
59             if(check(mid))    ans=mid,l=mid;
60             else            r=mid;
61         }
62         printf("%.0f\n",ans*100);
63     }
64     return 0;
65 }
View Code

猜你喜欢

转载自www.cnblogs.com/ibilllee/p/9263624.html