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