二分搜索,最大化平均值 Poj-3111

題目鏈接: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;
}

 

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