Educational Codeforces Round 21 E - Selling Souvenirs(三分or贪心背包)

题目链接:Educational Codeforces Round 21 E - Selling Souvenirs

题意:

有n个物品,每个物品有一个重量和价值,现在有一个m大的背包,问你最大能装多少价值。

题解:

做法一:

这题是加强版的01背包,不过有个特别的地方就是w只有三种。

所以可以枚举其中一种重量,然后三分查找。

因为剩下两种重量的函数值是一个单峰函数(不会证明)。

注意:在三分整数的时候,当区间只包含3个点时,有一个点访问不到,要手动补。

 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=a;i<=b;i++)
 3 using namespace std;
 4 typedef long long ll;
 5 const int N=1e5+7;
 6 
 7 int n,m,sum;
 8 ll ans,pre[4][N];
 9 vector<int>a[4];
10 
11 ll check(int mid,int have)
12 {
13     int one=have-2*mid;
14     if(one>a[1].size())one=a[1].size();
15     return pre[2][mid]+pre[1][one];
16 }
17 
18 ll del(int have)
19 {
20     int l=0,r=a[2].size();
21     r=min(r,have/2);
22     while(l<r-1)
23     {
24         int mid=l+r>>1,mid2=r+mid>>1;
25         if(check(mid,have)>check(mid2,have))r=mid2;
26         else l=mid;
27     }
28     return max(max(check(l,have),check(r,have)),check(0,have));
29 }
30 
31 int main(){
32     scanf("%d%d",&n,&m);
33     a[1].push_back(0),a[2].push_back(0),a[3].push_back(0);
34     F(i,1,n)
35     {
36         int x,y;
37         scanf("%d%d",&x,&y);
38         a[x].push_back(y);
39         sum+=x,ans+=y;
40     }
41     if(m>=sum){printf("%lld\n",ans);return 0;}
42     ans=0;
43     sort(a[1].begin(),a[1].end(),greater<int>());
44     sort(a[2].begin(),a[2].end(),greater<int>());
45     sort(a[3].begin(),a[3].end(),greater<int>());
46     F(k,1,3)F(i,0,a[k].size()-1)pre[k][i+1]=pre[k][i]+a[k][i];
47     F(i,0,a[3].size())if(i*3<=m)ans=max(ans,del(m-i*3)+pre[3][i]);
48     printf("%lld\n",ans);
49     return 0;
50 }
View Code

 做法二:

大范围贪心,小范围DP

在m比较大的时候,显然选择性价比高的物品比较好,所以按照单位重量的价值排序。

从前往后选,如果m刚好等于这样选出来的重量,那必然这个答案是最优解。

如果选择的重量为m-1,m-2,那么这里就要DP一下。

这里有几种情况,要从已经选择的物品中每一种重量的物品都要挑一个出来。

这样能为后面的物品腾出空间。

比如这组数据

3 6

1 100

3 101

3 101

如果按照之前的贪心选出来,肯定是选第一个和第二个,此时对剩余容量进行DP。

如果不将第一个物品挑出来,第三个物品永远也放不进去。

 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=a;i<=b;i++)
 3 using namespace std;
 4 typedef long long ll;
 5 typedef pair<int,int> P;
 6 const int N=1e5+7;
 7 
 8 ll ans,dp[N];
 9 int ed,n,m;
10 struct node
11 {
12     int w,c;
13     double val;
14     node(int a=0,int b=0):w(a),c(b){}
15     bool operator<(const node &b)const{return val>b.val;}
16 }a[N],tmp[N];
17 
18 ll DP()
19 {
20     F(i,1,ed)for(int j=m;j>=tmp[i].w;j--)
21         dp[j]=max(dp[j],dp[j-tmp[i].w]+tmp[i].c);
22     return dp[m];
23 }
24 
25 int main()
26 {
27 
28     scanf("%d%d",&n,&m);ans=0;
29     F(i,1,n)scanf("%d%d",&a[i].w,&a[i].c),a[i].val=1.0*a[i].c/a[i].w;
30     sort(a+1,a+1+n);
31     int tp[4];
32     memset(tp,-1,sizeof(tp));
33     F(i,1,n)
34     {
35         if(m<30)
36         {
37             ed=0;
38             while(i<=n)tmp[++ed]=a[i],i++;
39             F(ii,1,3)if(~tp[ii])tmp[++ed]=node(ii,tp[ii]),m+=ii,ans-=tp[ii];
40             ans+=DP();
41             break;
42         }
43         ans+=a[i].c;
44         m-=a[i].w;
45         tp[a[i].w]=a[i].c;
46     }
47     printf("%lld\n",ans);
48     return 0;
49 }
View Code

 

posted @ 2017-05-26 17:15  bin_gege  阅读(145)  评论(0编辑  收藏  举报