[KCOJ20170214]又一个背包
| 題目描述Description |
| 小W要去軍訓(xùn)了!由于軍訓(xùn)基地是封閉的,小W在軍訓(xùn)期間將無法離開軍訓(xùn)基地。所以他沒有辦法出去買他最愛吃的零食。萬般無奈的小W只好事先買好他愛吃的零食,裝在背包里帶入軍訓(xùn)基地。市場(chǎng)里的零食琳瑯滿目,縱然小W想把他們都帶走,然而小W的背包只有有限的容量。帶哪些零食好呢?小W給每種零食都評(píng)估了一個(gè)他的喜愛程度。另外,由于市場(chǎng)的零食都是散稱售賣的,所以一種零食可以只買一部分帶走。現(xiàn)在小W希望能挑選出最合適的購買方案,使得所購買的零食能裝進(jìn)背包且喜愛程度總分最大。因?yàn)榱闶车姆N類實(shí)在是太多了,所以小W找到了聰明的你,希望你能盡快(軍訓(xùn)的車隊(duì)即將出發(fā),時(shí)間緊迫)告訴他購買方案。 |
| 輸入描述Input Description |
|
第一行兩個(gè)整數(shù)n和w,分別表示有n種零食種類和背包總?cè)萘俊=酉聛韓行,每行兩個(gè)整數(shù)ci和vi,分別表示第i種食品占的體積和小W的喜愛程度。 |
| 輸出描述Output Description |
| 一行一個(gè)數(shù)字,表示最優(yōu)購買方案下,所能獲得的最大喜愛程度總和。保留3位小數(shù)。 |
|
樣例輸入 Sample Input |
|
55 |
|
樣例輸出 Sample Output |
| 11.000 |
|
數(shù)據(jù)范圍及提示 Data Size & Hint |
| n<=2000000,w<=2*10^9,0<=ci<=100,0<=vi<=100 |
一道部分背包問題。這道題按性價(jià)比排序然后貪心取肯定是沒有問題的,但是復(fù)雜度是O(n log n)有點(diǎn)大,像我們學(xué)校OJ對(duì)于n=2000000的肯定是跑不下來的。所以我們要O(n)做這道題。乍一想,發(fā)現(xiàn)完全沒有思路,應(yīng)該有一點(diǎn)靈感就是類似于O(n)求第K大數(shù)一樣,一個(gè)用的是O(n log n)排序,一個(gè)是nth_element O(n)做的。于是我們就想分治做這道題,把問題分為更小的子問題。算出每個(gè)物品的性價(jià)比之后,我們nth_element求出中位數(shù),這樣這個(gè)數(shù)列的左邊就變成比中位數(shù)小的,右邊就變成比中位數(shù)大的。然后我們暴力掃一遍右邊的價(jià)值和,判斷一下,然后就好辦了。復(fù)雜度分析的話,這個(gè)東西1+1/2+1/4+1/8+...+1/2^n是小于2的,所以類似的話,復(fù)雜度就是O(n)。本題還有一個(gè)坑點(diǎ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是當(dāng)前背包容量
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
總結(jié)
以上是生活随笔為你收集整理的[KCOJ20170214]又一个背包的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CPU的高速缓存存储器知识整理
- 下一篇: Ubuntu 18.04 安装微信(附企