01分数规划模板

01分数规划

01分数规划问题是求性价比问题,比如说给出总价值和总花费让你求其二者比值的最大值

假设价值为\(a[i]\),花费为\(b[i]\),求:

\[\frac{\sum a[i]}{\sum b[i]}=ans \]

求其\(ans\)的最大值。

我们移项发现:

\[F(ans)=\sum a[i]-ans*\sum b[i] \]

变化:

\[F(ans)=\sum (a[i]-ans*b[i]) \]

我们可以从上述公式知道如果是最大价值时\(F(ans)=0\),当\(F(ans)>0\)时说明我们二分的答案过小,所以缩小左边界,然后继续二分答案,知道\(F(ans)=0\)

链接:https://ac.nowcoder.com/acm/problem/14662
来源:牛客网

题目描述

小咪是一个土豪手办狂魔,这次他去了一家店,发现了好多好多(n个)手办,但他是一个很怪的人,每次只想买k个手办,而且他要让他花的每一分钱都物超所值,即:买下来的东西的总价值/总花费=max。请你来看看,他会买哪些东西吧。

输入描述:

多组数据。
第一行一个整数T,为数据组数。
接下来有T组数据。
对于每组数据,第一行两个正整数n,k,如题。
接下来n行,每行有两个正整数ci,vi。分别为手办的花费和它对于小咪的价值。

输出描述:

对于每组数据,输出一个数,即能得到的总价值/总花费的最大值。精确至整数。

思路

求ans最大值:

\[\frac{总价值}{总花费}=ans \]

显然是01分数规划问题,对于01分数规划我们假设价值是\(a[]\),花费是\(b[]\),然后二分答案

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define DOF 0x7f7f7f7f
#define endl '\n'
#define mem(a,b) memset(a,b,sizeof(a))
#define debug(case,x); cout<<case<<"  : "<<x<<endl;
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef long long ll;
using namespace std;
const int maxn = 1e5 + 10;
const double eps=1e-7;
ll a[maxn],b[maxn],c[maxn];
ll n,k;

bool check(ll x){
    for(ll i=1;i<=n;++i){
        c[i]=a[i]-x*b[i];
    }
    sort(c+1,c+1+n,greater<ll>());
    ll sum=0;
    for(ll i=1;i<=k;++i){
        sum+=c[i];
    }
    return sum>=0;
}
int main()
{
    ll t;cin>>t;
    while(t--){
        cin>>n>>k;
        for(ll i=1;i<=n;++i)cin>>b[i]>>a[i];
        ll l=0,r=1e9,mid;
        while(l<=r){
            mid=l+r>>1;
            if(check(mid))l=mid+1;
            else r=mid-1;
        }
        cout<<r<<endl;

    }
}
posted @ 2020-07-15 17:49  waryan  阅读(163)  评论(0编辑  收藏  举报