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 } 
没有人能阻止我前进的步伐,除了我自己!
原文地址:https://www.cnblogs.com/proverbs/p/2853725.html