0/1分數規劃——最大化平均值

題目:

最大化平均值

有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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章