题意:
给定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 }