N个物品的体积为W1,W2......Wn(Wi为整数),与之相对应的价值为P1,P2......Pn(Pi为整数),从中选出K件物品(K <= N),使得单位体积的价值最大。
Input
第1行:包括2个数N, K(1 <= K <= N <= 50000)
第2 - N + 1行:每行2个数Wi, Pi(1 <= Wi, Pi <= 50000)
Output
输出单位体积的价值(用约分后的分数表示)。
Input示例
3 2 2 2
5 3
2 1
Output示例
3/4
Analysis分析
qwq与01分数规划打了场遭遇战
贪心 w/v 被证明是错误的,因为我写完全WA了
而且样例就直接卡掉了这个贪心策略
那么我们可以一步一步来,首先记答案为 :
那么经过简单的数学变换我们得到:
注意,当分母为一的时候也,,,= =
然后有:
即:
那么我们二分这个R,使等式的结果无限接近 0 即可
Emmmmm
(其实没推清楚)
Code代码
1 #include<stdio.h> 2 #include<math.h> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 7 int n,k; 8 long long ansv,answ; 9 10 double eps = 0.000000001; 11 12 struct data{ 13 long long w,v; 14 double vrw; 15 }arr[1000000]; 16 17 bool cmp(const data &a,const data &b){ return a.vrw > b.vrw; } 18 19 bool check(long long &sumv,long long &sumw,double line){ 20 for(int i = 1;i <= n;i++) 21 arr[i].vrw = 1.0*arr[i].v-line*arr[i].w; 22 23 sort(arr+1,arr+1+n,cmp); 24 25 double tmp = 0; 26 sumv = 0,sumw = 0; 27 for(int i = 1;i <= k;i++) 28 sumv += arr[i].v, 29 sumw += arr[i].w, 30 tmp += arr[i].vrw; 31 32 return tmp >= 0; 33 } 34 35 long long gcd(long long a,long long b){ 36 if(a < b) swap(a,b); 37 return !b?a:gcd(b,a%b); 38 } 39 40 int main(){ 41 42 scanf("%d%d",&n,&k); 43 44 for(int i = 1;i <= n;i++) 45 scanf("%lld%lld",&arr[i].w,&arr[i].v); 46 47 double L = 0,R = 1000000; 48 long long sumv,sumw; 49 while(R-L > eps){ 50 // printf("%.8lf %.8lf\n",L,R); 51 double mid = (L+R)/2; 52 if(check(sumv,sumw,mid)) ansv = sumv, answ = sumw, L = mid; 53 else R = mid; 54 } 55 56 long long d = gcd(ansv,answ); 57 printf("%lld/%lld",ansv/d,answ/d); 58 59 return 0; 60 }