題目鏈接:https://vjudge.net/problem/POJ-3111
題目大意就是給你一堆有價值和重量的珠寶,問你如何挑選能夠是最終單位珠寶的價值最大。
首先我們的思路肯定是貪心,按照它們的單位價值進行排序,取最大的幾個。但是這是錯誤的。在這組數據中貪心就是錯誤的
k = 2
{w,v} = {2,2} , {5,3} , {2,1}
依照貪心的思想我們肯定會選取 {5,3}和{2,2}這一組,此時的單位價值x = 7/3 = 0.714,但實際情況我們取到了{2,2} + {2,1}
x = 0.75。故此可以得出貪心的思路是錯誤的。於是去枚舉珠寶單價的可能性,常規的暴力會TLE,於是我們是用二分的思想去枚舉將時間複雜度從O(n) 降爲log(n)。
講解來自《挑戰程序設計競賽》
設最大的單位價值爲x。那麼讓x成立的條件爲 ∑v / ∑w ≥ x 化簡可以得到 ∑v / ∑w ≥ x = > ∑v ≥ x * ∑w = ∑ (x*w) = > ∑ (v - x * w) ≥ 0,所以我們只要讓前k個物品都滿足這個條件,那麼此時的x就是符合條件的,我們再去找更大的就可以了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#define lson l m rt << 1
#define rson m+1 r rt << 1|1
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = 0x3f3f3f3f;
const int maxn = 1e6+10;
const int mod = 1000;
ll v[maxn],w[maxn];
ll T,n,k;
inline void fast()
{
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
}
struct Node
{
int v,w,id; //價值,重量,編號
double y;//排序時候判斷是否都滿足x
}a[maxn];
bool cmp(Node a,Node b) //從大到小排序
{
return a.y > b.y;
}
bool check(double x)
{
for(int i = 0;i < n;++i)
{
a[i].y = a[i].v - a[i].w*x; //推導出來的公式
}
sort(a,a+n,cmp);
double sum = 0;
for(int i = 0;i < k;++i) //如果sum最後大於零表示此時的X合適我們去二分更大的
sum += a[i].y;
return sum >= 0;
}
int main()
{
fast();
while(scanf("%lld %lld",&n,&k) != EOF)
{
for(int i = 0;i < n;++i)
{
scanf("%d %d",&a[i].v,&a[i].w);
a[i].id = i+1;
}
double l = 0,r = INF;
for(int i = 0;i < 100;++i)
{
double mid = (l + r)/2;
if(check(mid))
l = mid;
else
r = mid;
}
for(int i = 0;i < k;++i)
{
if(i == 0)
printf("%d",a[i].id);
else
printf(" %d",a[i].id);
}
printf("\n");
}
return 0;
}