基本问题:
有 n 个物品的重量和价值分别为 $w_i$ 和 $v_i$, 从中选 k 个物品使得单位重量的价值最大,即:
这个式子值最大。
POJ2976
题意:
n 场测试, 每场一个 $a_i$ 和 $b_i$,要求去掉 k 门课,使得下面的式子最大:
解法:
二分答案。
定义条件 C(x)= 可以选择使得单位重量的价值不小于x。
因此原问题就变成了求C(x)最大的x。假设选了某个集合S,则有:
$sum_{i - S}^{}V_i/sum_{i-S}^{}W_i$
这就变成了是否存在S满足下面的条件:
$sum_{i - S}^{}V_i/sum_{i-S}^{}W_i ge x$:
化简得:
$sum_{i-S}^{}(V_i-xW_i)ge0$
对式子左边得东西进行排序,贪心的进行选取,就变成了:
C(x)=$(V_i-xW_i)$从大到小排列中的前k个的和不小于0.
注意二分的时候ub和lb必须都是double,因为涉及到了除法
代码如下:
1 int N, K; 2 int a[MAXN], b[MAXN]; 3 double y[MAXN]; 4 5 bool C(double x) { 6 int t = N - K; 7 for (int i = 0; i < N; i++) y[i] = a[i] - x * b[i]; 8 sort(y, y + N); 9 double sum = 0.0; 10 for (int i = 0; i < t; i++) sum += y[N - i - 1]; 11 return sum >= 0.0; 12 } 13 14 void solve() { 15 double ub = INF - 1, lb = 0; 16 while (ub - lb > EPS) { 17 double mid = (ub + lb)/2; 18 if (C(mid)) { 19 //cout << "true: " << mid << endl; 20 lb = mid; 21 } 22 else { 23 //cout << "false: " << mid << endl; 24 ub = mid; 25 } 26 } 27 cout << round(100 * lb) << endl; 28 return; 29 } 30 31 int main() { 32 #ifndef ONLINE_JUDGE 33 FILE *stream1; 34 freopen_s(&stream1, "input.txt", "r", stdin); 35 #endif // !ONLINE_JUDGE 36 while (cin >> N >> K) { 37 if (N == 0 && K == 0) break; 38 for (int i = 0; i < N; i++) cin >> a[i]; 39 for (int i = 0; i < N; i++) cin >> b[i]; 40 solve(); 41 } 42 return 0; 43 }