wyh的物品(二分)

题目描述 

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

说明

对于样例来说,我们选择第一个物品和第三个物品,达到最优目的

思路

前提我们要知道的一个公式:

物品价值(v) = 单位价值*物品重量(w)
  • 1
  • 2

对于任意的单位价值m,我们都可以发现: 
1、对于任意的一个物品,物品实际价值与对于任意单位价值的关系只有三种情况:

1、x = 物品实际价值(v) -  (任意单位价值(mid)*物品重量(w)) == 0;
这说明:任意单位价值(mid)==实际单位价值。
2、x = 物品实际价值(v) -  (任意单位价值(mid)*物品重量(w)) > 0;
这说明:任意单位价值(mid)<实际单位价值。
3、x = 物品实际价值(v) -  (任意单位价值(mid)*物品重量(w)) < 0;
这说明:任意单位价值(mid)>实际单位价值。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这里对应着核心代码:s[i] = v[i] - mid*w[i];

 2、我们将所有这些实际价值与单位价值之差分别存储到一个数组当中,为了保证任意单位价值最大,我们取前k大的差值(x)。 

这里不太好想,我们换一个思路去思考,x值越大,就说明mid值越小,就说明还有比mid更大实际单位价值的值需要我们去找,我们的目的就是要找到更大的mid值呀。 
这里对应着核心代码:sort(s,s+n,cmp);

3、我们把选择出的前k个差值相加,得到前k个差值最大的物品实际价值与物品对于任意单位价值(n)所求得的物品相对价值之差的之和(ss)。 
这个值有两种情况

ss>=0 //任意的单位价值n取小了,导致实际价值还有剩余,还有更大的n。
ss<0  //任意的单位价值n取大了,导致实际价值都不可能满足由这个单位价值算出来的总价值。

AC:代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
const int maxn = (int)1e5+5; 
int w[maxn],v[maxn];
double s[maxn]; 
int n,k;
using namespace std;
int cmp(double x,double y)
{
	return x>y;
}
int slove(double mid)
{
	double ss = 0;
	for(int i = 0;i<n;i++)
	{
		s[i] = 1.0*v[i] - w[i]*mid;
	}
	sort(s,s+n,cmp);
	for(int i = 0;i<k;i++)
	{
		ss += s[i];
	}
	if(ss>=0) return 1;
	else return 0;
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		scanf("%d %d",&n,&k);
		double low = 0,high = 100000,mid;
		for(int i = 0;i<n;i++)
		{
			scanf("%d %d",&w[i],&v[i]);
		}
		while(high - low >0.00001)
		{
			mid = (low + high)/2.0;
			if(slove(mid)) low = mid;
			else high = mid;

		}
		printf("%.2lf\n",low);
	}
	return 0;
}


posted @ 2018-04-08 17:29  Nlifea  阅读(369)  评论(0编辑  收藏  举报