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

什么是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.

你可能感兴趣的:(test)