POJ2976(01分数规划+二分)

来源:互联网 发布:橡皮章app软件 编辑:程序博客网 时间:2024/05/22 11:56

题目大意:给你n对a,b,现在让你删除其中k对,使得剩下的n-k对a,b的Σa/Σb的值最大。(所有的a<=b)


这是我第一次做01分数规划的题,写得可能有点辣鸡。结果可以这样写a·x/b·xabx为向量,x∈{0,1}。x = 0表示不选否则表示选。易知n个x中有k个0。令p = a·x/b·x 。则有ax - p*bx = 0;定义函数f(p) = max{ax - p*bx}。当且仅当f(p) = 0时有最优解,设*p为最优解。因此我们使用二分法枚举p。但是,问题来了,我们在求f(p)的时候连向量x都不知道,怎么办?先提一下公因式f(*p) = (a - p*b)x。因此我们只需要求出最大的n-k个ai - *p*bi,然后判断f(p)的值,如果f(p) = 0,则有p = *p,此时为最优解;如果f(p) > 0 那么p < a·x/b·x

说明此时的p不是最优解,取小了,同理,如果f(p)<0则说明p取大了。

//使用scanf的时候此题推荐用c++编译器,不然WA
#include<cstdio>#include<algorithm>#include<cstring>#define MAXN 1005#define eps 0.00000001using namespace std;double a[MAXN],b[MAXN];int n,k;int main(){while(scanf("%d%d",&n,&k) != EOF&&n+k){for(int i = 0; i < n; i++)scanf("%lf",&a[i]);for(int i = 0; i < n; i++)scanf("%lf",&b[i]);double L = 0.0;double R = 1.0;double temp[MAXN];double mid;while(R-L > eps){mid  = (L+R)*1.0/2;for(int i = 0; i < n; i++)temp[i] = a[i] - mid*b[i];sort(temp,temp+n);double sum = 0;for(int i = k; i < n; i++)sum += temp[i];if(sum > 0)//貌似要写成if(sum > 0)不能直接写成if(sum) L = mid;else R = mid;}printf("%.0lf\n",mid*100);}}


0 0
原创粉丝点击