poj2976(0-1 分数规划)

poj2976(0-1 分数规划)

题意

给定n个二元组 ( a i , b i ) (a_{i},b_{i}) (ai,bi)除去n个,剩下的n-k组成集合S作 ∑ i ∈ S a i ∑ i ∈ S b i \frac{\sum_{i\in S}a_{i}}{\sum_{i\in S}b_{i}} iSbiiSai使其达到最大,原题还让将其取到最近整数!

0-1分数规划

这道题是一道很典型的0-1分数规划,网上的资源看了许多,但是好像没有人介绍在求解答案的时候二分的依据,也没有人解释为何要求解max(F(L)),在这里,我将给出解释。
首先还是对整个算法大概做个描述,具体细节一会解释
1.记 F ( L ) = ∑ i = 1 i = n ( a i − L b i ) x i F(L)=\sum_{i=1}^{i=n}(a_{i}-Lb_{i})x_{i} F(L)=i=1i=n(aiLbi)xi其中 ∑ i = 1 i = n x i = n − k \sum_{i=1}^{i=n}x_{i}=n-k i=1i=nxi=nk
2.由上面的表达式可以知道对于固定的L使得F(L)最大时即 m a x ( F ( L ) ) max(F(L)) max(F(L))为将 a i − L b i a_{i}-Lb_{i} aiLbi进行排序取前n-k大的元素,使其 x i = 1 x_{i}=1 xi=1其余为0,注意这里是在求F(L)的最值,而不是 ∑ i ∈ S a i ∑ i ∈ S b i \frac{\sum_{i\in S}a_{i}}{\sum_{i\in S}b_{i}} iSbiiSai的最值,
3.记 m a x ( ∑ i ∈ S a i ∑ i ∈ S b i ) = a n s max(\frac{\sum_{i\in S}a_{i}}{\sum_{i\in S}b_{i}})=ans maxiSbiiSai=ans对L进行二分,
当maxF(L)>0的时候则有L<max,
当maxF(L)<0时,L>max,
于是根据上两条进行二分,直到找到使得max(F(L))的L,此时的L==ans

在这里我们着重解释第3步中的二分的想法是怎么来的,其余未明白部分见大佬文章

好啦下面就开始了

对第3条的分析

1.首先对,“当maxF(L)>0的时候则有L<max”,进行解释

F ( L ) = ∑ i = 1 i = n ( a i x i ) − L ∑ i = 1 i = n ( b i x i ) = C F(L)=\sum_{i=1}^{i=n}(a_{i}x_{i})-L\sum_{i=1}^{i=n}(b_{i}x_{i})=C F(L)=i=1i=n(aixi)Li=1i=n(bixi)=C
我们先忘掉上述的结论,重新给出一个结论:
对于某一L,若存在序列 x i x_{i} xi满足其和未n-k,且使得F(L)>0的时候则有L<max,证明如下:
F ( L ) = ∑ i = 1 i = n ( a i x i ) − L ∑ i = 1 i = n ( b i x i ) = C > 0 F(L)=\sum_{i=1}^{i=n}(a_{i}x_{i})-L\sum_{i=1}^{i=n}(b_{i}x_{i})=C>0 F(L)=i=1i=n(aixi)Li=1i=n(bixi)=C>0
∑ i = 1 i = n ( a i x i ) = C + L ∑ i = 1 i = n ( b i x i ) \sum_{i=1}^{i=n}(a_{i}x_{i})=C+L\sum_{i=1}^{i=n}(b_{i}x_{i}) i=1i=n(aixi)=C+Li=1i=n(bixi)
∑ i = 1 i = n ( a i x i ) ∑ i = 1 i = n ( b i x i ) = C ∑ i = 1 i = n ( b i x i ) + L = D \frac{\sum_{i=1}^{i=n}(a_{i}x_{i})}{\sum_{i=1}^{i=n}(b_{i}x_{i})}=\frac{C}{\sum_{i=1}^{i=n}(b_{i}x_{i})}+L=D i=1i=n(bixi)i=1i=n(aixi)=i=1i=n(bixi)C+L=D
根据上式,可以发现,存在xi使得表达式 ∑ i = 1 i = n ( a i x i ) ∑ i = 1 i = n ( b i x i ) \frac{\sum_{i=1}^{i=n}(a_{i}x_{i})}{\sum_{i=1}^{i=n}(b_{i}x_{i})} i=1i=n(bixi)i=1i=n(aixi)的值D>L,于是L比目标表达式最值max要小,因为max(F(L))>F(L),若存在xi使得F(L)>0,则根据不等式传递性必有max(F(L))>F(L)>0, 并且使用max(F(L))在判断下面证明也能用到,节约了代码量!

2.接下来对"当maxF(L)<0的时候则有L>max"解释

F(L)<maxF(L)<0,则可以知道对所有 x i x_{i} xi F ( L ) = ∑ i = 1 i = n ( a i x i ) − L ∑ i = 1 i = n ( b i x i ) = C < 0 F(L)=\sum_{i=1}^{i=n}(a_{i}x_{i})-L\sum_{i=1}^{i=n}(b_{i}x_{i})=C<0 F(L)=i=1i=n(aixi)Li=1i=n(bixi)=C<0,
对等式按照上面的方式进行变形
∑ i = 1 i = n ( a i x i ) ∑ i = 1 i = n ( b i x i ) = C ∑ i = 1 i = n ( b i x i ) + L = D < L \frac{\sum_{i=1}^{i=n}(a_{i}x_{i})}{\sum_{i=1}^{i=n}(b_{i}x_{i})}=\frac{C}{\sum_{i=1}^{i=n}(b_{i}x_{i})}+L=D<L i=1i=n(bixi)i=1i=n(aixi)=i=1i=n(bixi)C+L=D<L对任意 x i x_{i} xi成立,对于使得 ∑ i = 1 i = n ( a i x i ) ∑ i = 1 i = n ( b i x i ) \frac{\sum_{i=1}^{i=n}(a_{i}x_{i})}{\sum_{i=1}^{i=n}(b_{i}x_{i})} i=1i=n(bixi)i=1i=n(aixi)取的最大值max得 x i x_{i} xi也有max<L

有了1,2得判据,就可以根据二分法进而得出答案了.

代码如下:

#include<iostream>
#include<cmath>
#include<algorithm>
#define maxsize 1004
using namespace std;
int n,k;
double a[maxsize],b[maxsize];
bool justify(double r)
{
	double d[maxsize];
	for(int i=0;i<n;i++){
		d[i]=a[i]-r*b[i];
		// cout<<d[i]<<endl;
	}
	sort(d,d+n);
	double sum=0;
	for(int i=k;i<n;i++)sum+=d[i];
	// cout<<sum<<endl;
	return sum>0;
}
int main()
{
	// freopen("ini","r",stdin); 
	while(~scanf("%d%d",&n,&k)&&(n!=0||k!=0)){
		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,r=1;
		while(fabs(r-l)>1e-6)
		{
			double mid=(l+r)/2;
			if(justify(mid))l=mid;
			else r=mid;
		}
		int ans=(int)((r+0.005)*100);
		cout<<ans<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值