POJ 3111

题意:给定n个结点,每个结点有v,w两个值,求含k个结点的子集,使得sum(v)/sum(w)最大。

题解:0,1分数规划,求g=sum(v)/sum(w)最大,二分枚举g的值,求sum(v-g*w)的最小值,即选出n个结点中v-g*w的最小的k个元素,加起来与0进行比较。0,1分数规划详情请参见OI论文《最小割模型在信息学竞赛中的应用》

View Code
 1 #include<cstdio>

 2 #include<cstring>

 3 #include<algorithm>

 4 using namespace std;

 5 const int N=100005;

 6 const double inf=1e50,eps=1e-8;

 7 int pre[N],n,k;

 8 struct data

 9 {

10     double w,v;

11     int id;

12 }po[N];

13 double xx;

14 bool comp(data a,data b)

15 {

16     return a.v-xx*a.w>b.v-xx*b.w;

17 }

18 bool comp2(data a,data b)

19 {

20     return a.id<b.id;

21 }

22 double solve(double x)

23 {

24     xx=x;

25     nth_element(po,po+k-1,po+n,comp);

26     double ans=0;

27     for(int i=0;i<k;i++)

28         ans+=po[i].v-xx*po[i].w;

29     return ans;

30 }

31 int main()

32 {

33     while(scanf("%d%d",&n,&k)!=EOF)

34     {

35         for(int i=0;i<n;i++)

36             scanf("%lf%lf",&po[i].v,&po[i].w),po[i].id=i+1;

37         double ll=0,rr=1e7,mid;

38         while(ll<rr)

39         {

40             mid=(ll+rr)/2.0;

41             if(solve(mid)<-eps)

42                 rr=mid-eps;

43             else

44                 ll=mid+eps;

45         }

46         sort(po,po+k,comp2);

47         for(int i=0;i<k-1;i++)

48             printf("%d ",po[i].id);

49         printf("%d\n",po[k-1].id);

50     }

51     return 0;

52 }

你可能感兴趣的:(poj)