POJ2976 Dropping tests——01分数规划——Pku2976

时间:2022-12-01 18:39:50

什么是01分数规划:

给出n个分数ai/bi,选出m个(m<=n)使得∑(ai)/∑(bi){其中i是被选出的分数编号}达到最大值。

 

01 分数规划的两种方法:

1、二分法

二分一个答案k,令ci=ai-k*bi,并将ci排序,选出最大的m个,如果∑(ci){1<=i<=m}>=0,那么提高答案k的下界,否则降低上界,直到k的精度满足要求为止。

2、Dinkelbach迭代法

随意构造一个答案k,令ci=ai-k*bi,并将ci排序,选出最大的m个,令q=∑(ai)/∑(bi){1<=i<=m}与k的差在精度范围内就输出,否则令k=q,直至满足精度要求。

 

总结:

两种方法各有利弊,二分法精度较高,容易理解和证明,然而速度较慢。而Dinkelbach迭代法速度较快,但精度低,不易理解和证明。可视情况选择解题方法。

 

给出本题的代码(Dinkelbach迭代法):

Program Dropping_Tests;//By_Thispoet
Const
	maxn=1000;
Var
	i,m,n							:Longint;
	j,p								:Int64;
	k,q								:Extended;
	a,b								:Array[1..maxn]of Int64;
	c								:Array[1..maxn]of Extended;
	
Procedure Qsort(l,r:Longint);
var i,j		:Longint;
	tmp		:Int64;
	k,temp	:Extended;
begin
	i:=l;j:=r;k:=c[(i+j)>>1];
	repeat
		while c[i]>k do inc(i);
		while c[j]<k do dec(j);
		if i<=j then
			begin
				tmp:=a[i];a[i]:=a[j];a[j]:=tmp;
				tmp:=b[i];b[i]:=b[j];b[j]:=tmp;
				temp:=c[i];c[i]:=c[j];c[j]:=temp;
				inc(i);dec(j);
			end;
	until i>j;
	if l<j then Qsort(l,j);
	if i<r then Qsort(i,r);
end;
	
	
BEGIN

	readln(n,m);
	
	while not ((n=0)and(m=0)) do
		begin
			
			m:=n-m;
			for i:=1 to n do read(a[i]);readln;
			for i:=1 to n do read(b[i]);readln;
			q:=0.5;
			
			repeat
			
				k:=q;
				j:=0;p:=0;
				for i:=1 to n do c[i]:=a[i]-b[i]*k;
				Qsort(1,n);
				for i:=1 to m do
					begin
						inc(j,a[i]);
						inc(p,b[i]);
					end;
				q:=j/p;
				
			until abs(k-q)<=0.00001;
			
			writeln(round(100*k));
			
			readln(n,m);
			
		end;

END.