wyh的物品
时间限制:C/C++ 5秒,其他语言10秒
空间限制:C/C++ 262144K,其他语言524288K
题目描述
wyh学长现在手里有n个物品,这n个物品的重量和价值都告诉你,然后现在让你从中选取k个,问你在所有可能选取的方案中,最大的单位价值为多少(单位价值为选取的k个物品的总价值和总重量的比值)
输入描述:
输入第一行一个整数T(1<=T<=10)
接下来有T组测试数据,对于每组测试数据,第一行输入两个数n和k(1<=k<=n<=100000)
接下来有n行,每行两个是a和b,代表这个物品的重量和价值
输出描述:
对于每组测试数据,输出对应答案,结果保留两位小数
示例1
输入
1
3 2
2 2
5 3
2 1
输出
0.75
说明
对于样例来说,我们选择第一个物品和第三个物品,达到最优目的
题意
给你n个物品,让你挑出k个,使其的单位价值最大。
再简单一点:最大化平均值。
思路
前提我们要知道的一个公式:
物品价值(b) = 单位价值(realm)*物品重量(a)
对于任意的单位价值m,我们都可以发现:
1、对于任意的一个物品,物品实际价值与对于任意单位价值的关系只有三种情况:
1、x = 物品实际价值(b) - (任意单位价值(m)*物品重量(a)) == 0;
这说明:任意单位价值(m)==实际单位价值(realm)。
2、x = 物品实际价值(b) - (任意单位价值(m)*物品重量(a)) > 0;
这说明:任意单位价值(m)<实际单位价值(realm)。
3、x = 物品实际价值(b) - (任意单位价值(m)*物品重量(a)) < 0;
这说明:任意单位价值(m)>实际单位价值(realm)。
这里对应着核心代码:peizhong[i] = b[i] - ans*a[i];
2、我们将所有这些实际价值与单位价值之差分别存储到一个数组当中,为了保证任意单位价值最大,我们取前k大的差值(x)。
这里不太好想,我们换一个思路去思考,x值越大,就说明m值越小,就说明还有比m更大realm的值需要我们去找,我们的目的就是要找到更大的m值呀w。
这里对应着核心代码:sort(peizhong,peizhong+n,cmp);
3、我们把选择出的前k个差值相加,得到前k个差值最大的物品实际价值与物品对于任意单位价值(n)所求得的物品相对价值之差的之和(sum)。
这个值有两种情况
sum>=0 //任意的单位价值n取小了,导致实际价值还有剩余,还有更大的n。
sum<0 //任意的单位价值n取大了,导致实际价值都不可能满足由这个单位价值算出来的总价值。
4、使用二分进一步缩小n值的取值范围,直到满足我们规定的最小精度。
坑点
怎么样都想不出来【菜
容易想成背包问题、dp、暴力等等…..
AC代码
#include<bits/stdc++.h>
using namespace std;
int n,k;
typedef long long ll;
double a[100006],b[100006];
double peizhong[100006];
bool cmp(double a,double b)
{
return a>b;
}
bool judge(double ans)
{
/*核心的核心*/
for(int i = 0 ; i < n ; i++){
peizhong[i] = b[i] - ans*a[i];
}
/*贪心核心*/
sort(peizhong,peizhong+n,cmp);
double sum = 0;
for(int i = 0 ; i < k ; i++){
sum+=peizhong[i];
}
return sum>=0;
}
void solve(void)
{
int t;
cin>>t;
while(t--)
{
cin>>n>>k;
for(int i = 0 ; i < n ; i++){
cin>>a[i]>>b[i];
}
double l = 0,r = 100000;
double mid=0;
/*二分查找核心*/
while(r-l>=0.0001)
{
mid = (l+r)/2.0;
if(judge(mid)){
l = mid;
}
else r = mid;
}
printf("%.2f\n",mid);
}
}
int main(void)
{
solve();
return 0;
}