POJ2976(01分数规划+二分)

题目大意:给你n对a,b,现在让你删除其中k对,使得剩下的n-k对a,b的Σa/Σb的值最大。(所有的a<=b)


这是我第一次做01分数规划的题,写得可能有点辣鸡。结果可以这样写a·x/b·xabx为向量,x∈{0,1}。x = 0表示不选否则表示选。易知n个x中有k个0。令p = a·x/b·x 。则有ax - p*bx = 0;定义函数f(p) = max{ax - p*bx}。当且仅当f(p) = 0时有最优解,设*p为最优解。因此我们使用二分法枚举p。但是,问题来了,我们在求f(p)的时候连向量x都不知道,怎么办?先提一下公因式f(*p) = (a - p*b)x。因此我们只需要求出最大的n-k个ai - *p*bi,然后判断f(p)的值,如果f(p) = 0,则有p = *p,此时为最优解;如果f(p) > 0 那么p <  a·x/b·x

说明此时的p不是最优解,取小了,同理,如果f(p)<0则说明p取大了。

//使用scanf的时候此题推荐用c++编译器,不然WA
#include<cstdio>
#include<algorithm>
#include<cstring>
#define MAXN 1005
#define eps 0.00000001
using namespace std;
double a[MAXN],b[MAXN];
int n,k;
int main()
{
	while(scanf("%d%d",&n,&k) != EOF&&n+k)
	{
		for(int i = 0; i < n; i++)
			scanf("%lf",&a[i]);
		for(int i = 0; i < n; i++)
			scanf("%lf",&b[i]);
		
		double L = 0.0;
		double R = 1.0;
		double temp[MAXN];
		
		double mid;
		while(R-L > eps)
		{
			mid  = (L+R)*1.0/2;
			for(int i = 0; i < n; i++)
				temp[i] = a[i] - mid*b[i];
			sort(temp,temp+n);
			double sum = 0;
			for(int i = k; i < n; i++)
				sum += temp[i];
			if(sum > 0)//貌似要写成if(sum > 0)不能直接写成if(sum) 
				L = mid;
			else 
				R = mid;
		}
		printf("%.0lf\n",mid*100);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值