有n個物品的重量和價值分別是w[i]和v[i],從中選出K個物品使得單位重量的價值最大。
1<=k<=n<=10^4
1<=w[i],v[i]<=10^6
一般想到的是按單位價值對物品排序,然後貪心選取,但是這個方法是錯誤的,對於有樣例不滿足。我們一般用二分搜索來做(其實這就是一個01分數規劃)
我們定義:
條件 C(x) :=可以選k個物品使得單位重量的價值不小於x。
因此原問題轉換成了求解滿足條件C(x)的最大x。那麼怎麼判斷C(x)是否滿足?
變形:(sigma(v[i])/sigma(w[i]))>=x (i 屬於我們選擇的某個物品集合S)
進一步:sigma(v[i]-x*w[i])>=0
於是:條件滿足等價於選最大的k個和不小於0.於是排序貪心選擇可以判斷,每次判斷的復雜度是O(nlogn)。
代碼:
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn=1e4;
const double eps=1e-5;
int w[maxn],v[maxn],n,k;
double y[maxn];
bool check(double r)
{
for(int i=0;i<n;i++){
y[i]=v[i]-r*w[i];
}
sort(y,y+n);
reverse(y,y+n);
double sum=0;
for(int i=0;i<k;i++)
{
sum+=y[i];
}
return sum>=0;
}
int main()
{
while(cin>>n)
{
cin>>k;
for(int i=0;i<n;i++)
cin>>w[i]>>v[i];
double lb=0,ub=1e6;
while(ub-lb>eps)
{
double mid=(lb+ub)/2;
if(check(mid)) lb=mid;
else ub=mid;
}
printf("%.2f\n",ub);
}
return 0;
}