01分数规划
01分数规划问题是求性价比问题,比如说给出总价值和总花费让你求其二者比值的最大值
假设价值为
a
[
i
]
a[i]
a[i],花费为
b
[
i
]
b[i]
b[i],求:
∑
a
[
i
]
∑
b
[
i
]
=
a
n
s
\frac{\sum a[i]}{\sum b[i]}=ans
∑b[i]∑a[i]=ans
求其
a
n
s
ans
ans的最大值。
我们移项发现:
F
(
a
n
s
)
=
∑
a
[
i
]
−
a
n
s
∗
∑
b
[
i
]
F(ans)=\sum a[i]-ans*\sum b[i]
F(ans)=∑a[i]−ans∗∑b[i]
变化:
F
(
a
n
s
)
=
∑
(
a
[
i
]
−
a
n
s
∗
b
[
i
]
)
F(ans)=\sum (a[i]-ans*b[i])
F(ans)=∑(a[i]−ans∗b[i])
我们可以从上述公式知道如果是最大价值时
F
(
a
n
s
)
=
0
F(ans)=0
F(ans)=0,当
F
(
a
n
s
)
>
0
F(ans)>0
F(ans)>0时说明我们二分的答案过小,所以缩小左边界,然后继续二分答案,知道
F
(
a
n
s
)
=
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最大值:
总
价
值
总
花
费
=
a
n
s
\frac{总价值}{总花费}=ans
总花费总价值=ans
显然是01分数规划问题,对于01分数规划我们假设价值是
a
[
]
a[]
a[],花费是
b
[
]
b[]
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;
}
}