ACM Yougth的最大化

OpenSoucre發表於2014-04-09

Yougth的最大化

時間限制:1000 ms  |  記憶體限制:65535 KB
難度:4
 
描述

Yougth現在有n個物品的重量和價值分別是Wi和Vi,你能幫他從中選出k個物品使得單位重量的價值最大嗎?

 
輸入
有多組測試資料
每組測試資料第一行有兩個數n和k,接下來一行有n個數Wi和Vi。
(1<=k=n<=10000) (1<=Wi,Vi<=1000000)
輸出
輸出使得單位價值的最大值。(保留兩位小數)
樣例輸入
3 2
2 2
5 3
2 1
樣例輸出
0.75

典型的0-1分數規劃問題,用二分+貪心求解
首先必須知道單位重要的的最大價值的取值範圍,其最小為0,最大不超過單個物品的單位重量的最大價值
證明如下:
  假設第i個物品的單位重量的價值最大,則對於任意的第j個物品的有Vj/Wj<=Vi/Wi Vi*Wj-Vj*Wi >= 0

則j,i兩個物品的單位重量的價值為(Vi+Vj)/(Wi+Wj),
Vi/Wi-(Vi+Vj)/(Wi+Wj) = (Vi*Wj-Vj*Wi)/(Wi*(Wi+Wj)) >=0
Vi/Wi>=(Vi+Vj)/(Wi+Wj)
單位重量的的最大價值不超過單個物品的單位重量的最大價值
找到單位重量的的最大價值的範圍既可以用二分搜尋找到滿足條件的值即可
由於(v1+v2+...+vk)/(w1+w2+...+wk) = value
則(v1+v2+...+vk)=value*(w1+w2+...+wk)
二分搜尋時
如果value比單位重量的最大值大,則
(v1+v2+...+vk)-value*(w1+w2+...+wk) < 0 說明所求的值小於value
如果value比單位重量的最大值小,則
(v1+v2+...+vk)-value*(w1+w2+...+wk) > 0 說明所求值大於value

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <cstdio>
using namespace std;

struct Good{
    float w;
    float v;
    Good(double ww=0.0, double vv=0.0):w(ww),v(vv){}
};

vector<Good> goods(10005);
int n,k;

bool judge(float value){
    vector<float> diffValue(n);
    for(int i = 0 ; i < n; ++ i)
        diffValue[i] = goods[i].v-goods[i].w*value;
    sort(diffValue.begin(),diffValue.end());
    float sum = accumulate(diffValue.rbegin(),diffValue.rbegin()+k,0.0);
    return sum >= 0 ? true:false;
}

float binarySearch(float maxv){
    float left = 0, right = maxv;
    for(int i = 0; i < 100; ++ i){
        float mid =(left+right)/2;
        if(judge(mid)) left = mid;
        else right = mid;
    }
    return left;
}

int main(){
   while(cin >>n >> k){
        float maxv = 0;
        for(int i = 0 ; i < n; ++i){
            cin >>goods[i].w >>goods[i].v;
            maxv = max(maxv,goods[i].v/goods[i].w );
        }
        printf("%0.2f\n",binarySearch(maxv));
   }
}