[51nod] 1257 背包问题 V3

1257 背包问题 V3

基准时间限制:3 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
 
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 }
注意,当分母为一的时候也,,,= =

 

posted @ 2017-10-24 13:31  Leviaton  阅读(286)  评论(0编辑  收藏  举报