POJ 2976 01分数规划

题意:

 给定n个二元组(a,b),删除k个二元组,使得剩下的a元素之和与b元素之和的比率最大(比率最后乘100输出)

 

题解:

最裸的01分数规划,以此题为例讲述如何构造。

 

设:xi∈{0,1},表示第i个二元组是否留下,p为比率,P为p的最大值,即比例的最大值(注意区分大P于小p)

则:p=sigma(ai*xi)/sigma(bi*xi)   其中sigma(xi)=n-k

显然:对于所有可能的取得的 p 的值,p<=P

即:对于所有可能的xi的组合,sigma(ai*xi)/sigma(bi*xi)<=P

即:sigma(ai*xi)/sigma(bi*xi)的最大值等于P

即:sigma(ai*xi)-sigma(P*bi*xi)<=0,也就是sigma(ai*xi)-sigma(P*bi*xi)的最大值等于0

由于:sigma(ai*xi)-sigma(p*bi*xi)等价于sigma((ai-bi*p)*xi),sigma((ai-bi*P)*xi)的最大值就等于0

 

同理:

设:我们枚举的p的最大值为m(对于虽有的xi的组合,不一定存在m这个取值)

若m>P,sigma((ai-bi*P)*xi)的最大值小于0

若m<P,sigma((ai-bi*P)*xi)的最大值大于0

 

然后通过二分逼近的方法可以求出m=P~

 

市面上能够见到的01分数规划大都就是这么做~

 

View Code
 1 #include <iostream>

 2 #include <cstdlib>

 3 #include <cstring>

 4 #include <cstdio>

 5 #include <algorithm>

 6 

 7 #define N 1100

 8 

 9 using namespace std;

10 

11 struct PX

12 {

13     double a,b,c;

14 }px[N];

15 

16 int n,p;

17 double l,r,mid;

18 

19 inline bool cmp(const PX &a,const PX &b)

20 {

21     return a.c>b.c;

22 } 

23 

24 inline void read()

25 {

26     for(int i=1;i<=n;i++) scanf("%lf",&px[i].a);

27     for(int i=1;i<=n;i++) scanf("%lf",&px[i].b);

28 }

29 

30 inline bool check()

31 {

32     for(int i=1;i<=n;i++)

33         px[i].c=px[i].a-px[i].b*mid;

34     sort(px+1,px+1+n,cmp);

35     double ans=0.0;

36     for(int i=1;i<=n-p;i++) ans+=px[i].c;

37     if(ans<0.0) return true;

38     else return false;

39 }

40 

41 inline void go()

42 {

43     l=0.0; r=1.0;

44     while(r-l>1e-8)

45     {

46         mid=(l+r)/2.0;

47         if(check()) 

48             r=mid;

49         else l=mid;

50     }

51     printf("%.0lf\n",mid*100);

52 }

53 

54 int main()

55 {

56     while(scanf("%d%d",&n,&p),n||p) read(),go();

57     return 0;

58 } 

 

 

你可能感兴趣的:(poj)