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