牛客2018多校第五场 gpa 01分数规划

有关01分数规划的介绍 

首先01分数规划是处理这样一类问题的,给你n个二元组,这个两个元素设为a[i] ,b[i], a[i]是得到这
个物品所能得到的价值,b[i]是得到这个物品所付出的价值,让你求这样一个极值
   R  =  sigma(a[i] * x[i]) / sigma(b[i] * x[i])求他的最大或最小,这里我们以最大为例说事。


设 F(L) = sigma(a[i] * x[i]) - L * sigma(b[i] * x[i])    //注意此时的L和R的关系,其实L == R .
    化简  = sigma((a[i] - L * b[i]) * x[i])
    设 d[i] = a[i] - L * b[i]
    则 F(L) = sigma(d[i] * x[i])
    

    F(L)到底到底有什么用呢?
    我们假设F(L) > 0 则有 sigma(a[i] * x[i]) - L * sigma(b[i] * x[i]) > 0
    转化后得到 sigma(a[i] * x[i]) / sigma(b[i] * x[i]) > L
    也就是说当F(L) > 0 的时候有更大的L,也就是有更大的R,那么只要F(L) > 0我们就可以直接去
    找更大的L(R)直到F(L) 无限接近0为止,这里我们可以用二分去查找,理由是
    F(L) = sigma(d[i] * x[i]) ,d[i] 又是随着L增加而减少的(所以随着L增大,一定有一个点使得F(L)  ==0 ,
   这时再增大的话,就会导致F(L) < 0 [即L<0],此时的F(L) 没有实际意义,因为L不可能小于0,参数都
   是正的嘛),只要能找到一种sigma(d[i] * x[i])>=0的情况我们就可以继续往上找,说道这里直接分细
   化,上面说只要找到一组d[i]>=0的就可以low = mid 往上找了,这里到底有没有限制呢,当然有,限制就是上面的那三个分类,
(1)正常的情况(没有任何限制的)我们只要找到一个最大的d[i],d[i]>= 0就行了
因为是只要找到一种情况就行,我们没必要多找,但是前两天见到一个是限制必须选择n - k个的,那么就把现有的d[i]求出来,
排序,取最大的那n-k个的和,看大是否大于等于0就行了(POJ 2976)
(2)最优比率生成树,就是在我们选择的时候要找到一颗满足要求的数而已,一般都是求最小树
    或者最大树,然后看权值是否>=0.(POJ 2728)
(3)最优比率生成环,就是要求我们选择一个环,这个我习惯用SPFA,判断满足要求的环
(POJ 3621)

作者:Anxdada
链接:https://www.jianshu.com/p/4bc6037fe8e1
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

代码: 

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn = 1e5+5;
int a[maxn],b[maxn],k,n ;
double c[maxn];
const double eps = 1e-6;
bool check(double mid)
{
	double ans = 0;
	for(int i = 0; i<n; i++)
		c[i] = a[i] - mid*b[i];
	sort(c,c+n);
	for(int i = k; i<n; i++)
		ans  += c[i];
	return ans>=0;
}
void solve ()
{
	double l = 0,r = 1000000000;
	while(r-l>eps)
	{
		double mid = (l+r)/2;
		if(check(mid)) l = mid;
		else r = mid;
	}
	printf("%lf\n",l);
}
int main()
{
	scanf("%d%d",&n,&k); 
	for(int i = 0; i<n; i++)
	{
		scanf("%d",&b[i]);
	}
	for(int i = 0; i<n; i++)
	{
		scanf("%d",&a[i]);
		a[i]*=b[i];
	} 
	solve();
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值