題目:
最大化平均值
有n個物品的重量和價值分別是w;和vi。從中選出k個物品使得單位重量的價值最大。①限制條件
●1≤k≤n≤10^4
●1≤wi,vi≤10^6
輸入
n=3
(W,v) = {(2, 2),(5, 3),(2, 1))
輸出
0.75 (如果選0號和2號物品,平均價值是(2+1)/(2+2)=0.75)
分析:
-般最先想到的方法可能是把物品按照單位價值進行排序,從大到小貪心地進行選取。但是這個方法對於樣例輸人得到的結果
5/7=0.714。所以這個方法是不可行的。那麼應該如何求解呢?
實際上,對於這個問題使用二分搜索法可以很好地解決。我們定義
條件C(x):=可以選擇使得單位重量的價值不小於x
因此,原問題就變成了求滿足Cmp(x)的最大的x。那麼怎麼判斷Cmp(x)是否可行呢?假設我們選了某個物品的集合S,那麼它們的單量的價值是
因此就變成了判斷是否存在S滿足下面的條件
把這個不等式進行變形就得到
因此,可以對(vi-x*wi)的值進行排序貪心地進行選取。因此就變成了
Cmp(x)=(vi-x*wi)從大到小排列中的前k個的和不小於0)
每次判斷的複雜度是O(nlogn)。
實現:
//0/1分數規劃
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int n,k;
vector<int> w;
vector<int> v;
bool cmp(double x) {
vector<double> temp;
for(int i=0; i<n; ++i)
temp.push_back(v[i]-x*w[i]);
sort(temp.begin(),temp.end());
double sum=0;
for(int i=0; i<k; ++i)
sum+=temp[n-i-1];
return sum>=0;
}
int main() {
cin>>n>>k;
w.resize(n);
v.resize(n);
for(int i=0; i<n; ++i)
cin>>w[i];
for(int i=0; i<n; ++i)
cin>>v[i];
double l=0,r=1e9;
for(int i=0; i<100; ++i) {
double mid=(r+l)/2;
if(cmp(mid))
l=mid;
else r=mid;
}
cout<<l;
return 0;
}