zoukankan      html  css  js  c++  java
  • [KCOJ20170214]又一个背包

    题目描述 Description
    小W要去军训了!由于军训基地是封闭的,小W在军训期间将无法离开军训基地。所以他没有办法出去买他最爱吃的零食。万般无奈的小W只好事先买好他爱吃的零食,装在背包里带入军训基地。市场里的零食琳琅满目,纵然小W想把他们都带走,然而小W的背包只有有限的容量。带哪些零食好呢?小W给每种零食都评估了一个他的喜爱程度。另外,由于市场的零食都是散称售卖的,所以一种零食可以只买一部分带走。现在小W希望能挑选出最合适的购买方案,使得所购买的零食能装进背包且喜爱程度总分最大。因为零食的种类实在是太多了,所以小W找到了聪明的你,希望你能尽快(军训的车队即将出发,时间紧迫)告诉他购买方案。
    输入描述 Input Description

    第一行两个整数n和w,分别表示有n种零食种类和背包总容量。 接下来n行,每行两个整数ci和vi,分别表示第i种食品占的体积和小W的喜爱程度。

    输出描述 Output Description
    一行一个数字,表示最优购买方案下,所能获得的最大喜爱程度总和。保留3位小数。
    样例输入 Sample Input
    5 5
    1 5
    2 4
    3 3
    4 2
    5 1
    样例输出 Sample Output
    11.000
    数据范围及提示 Data Size & Hint
    n <= 2000000,w <= 2*10^9,0<=ci <= 100,0<=vi<=100

    一道部分背包问题。这道题按性价比排序然后贪心取肯定是没有问题的,但是复杂度是O(n log n)有点大,像我们学校OJ对于n=2000000的肯定是跑不下来的。所以我们要O(n)做这道题。乍一想,发现完全没有思路,应该有一点灵感就是类似于O(n)求第K大数一样,一个用的是O(n log n)排序,一个是nth_element O(n)做的。于是我们就想分治做这道题,把问题分为更小的子问题。算出每个物品的性价比之后,我们nth_element求出中位数,这样这个数列的左边就变成比中位数小的,右边就变成比中位数大的。然后我们暴力扫一遍右边的价值和,判断一下,然后就好办了。复杂度分析的话,这个东西1+1/2+1/4+1/8+...+1/2^n是小于2的,所以类似的话,复杂度就是O(n)。本题还有一个坑点,就是空间有可能是0!

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstdio>
     4 #include<cstdlib>
     5 #include<cstring>
     6 #include<queue>
     7 using namespace std;
     8 typedef long long LL;
     9 inline int read()
    10 {
    11     int x=0,f=1;char c=getchar();
    12     while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    13     while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    14     return x*f;
    15 }
    16 const int maxn=2000010;
    17 struct Item
    18 {
    19     double w,v,s;
    20     bool operator < (const Item &t)const  {return s<t.s;}
    21 }a[maxn];
    22 int n,ans;
    23 double V;
    24 double solve(int l,int r,double val)//val是当前背包容量 
    25 {
    26     if(l>r)return 0;
    27     if(l==r)
    28     {
    29         if(val<a[l].v)return val*a[l].s;
    30         else return a[l].w;
    31     }
    32     int mid=(l+r)/2;
    33     double sum=0,sum2=0;
    34     nth_element(a+l,a+mid,a+r+1);
    35     for(int i=mid+1;i<=r;i++)sum+=a[i].w,sum2+=a[i].v;
    36     //printf("%d %d %d %lf %lf %lf
    ",l,r,mid,sum,sum2,val);
    37     if(val>sum2)return sum+solve(l,mid,val-sum2);
    38     if(val==sum2)return sum;
    39     if(val<sum2)return solve(mid+1,r,val);
    40 }
    41 int main()
    42 {
    43     n=read();V=(double)read();
    44     int i=1;
    45     while(i<=n)
    46     {
    47          a[i].v=(double)read();a[i].w=(double)read();
    48          if(a[i].v==0)ans+=a[i].w,n--;
    49          else a[i].s=a[i].w/a[i].v,i++;
    50     }
    51     printf("%.3f
    ",ans+solve(1,n,V));
    52     return 0;
    53 }
    View Code
  • 相关阅读:
    C# 打开模态对话框 和打开文件夹
    C# 统计字符串出现的个数
    html table内容不随标题滚动
    log4net 局部代码 看不懂....
    js的replace, 高亮, insertAdjacentHTML , tbody.innerHTML
    python之tkinter使用举例-Button
    使用pygal_maps_world.i18n中数据画各大洲地图
    使用pygal_maps_world展示世界地图
    python之pygal:掷两个不同的骰子并统计大小出现次数
    python之文件目录操作
  • 原文地址:https://www.cnblogs.com/FYH-SSGSS/p/6403558.html
Copyright © 2011-2022 走看看