zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 21 E

    题目链接: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
    ",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
    ",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
    ",ans);
    48     return 0;
    49 }
    View Code
  • 相关阅读:
    各类免费资料及书籍索引大全(珍藏版)
    转—如何写一篇好的技术博客
    如何写技术博客
    Spring + Spring MVC + Mybatis 框架整合
    Httpclient 4.5.2 请求http、https和proxy
    HttpClient4.5.2 连接池原理及注意事项
    php加密数字字符串,使用凯撒密码原理
    php 阿里云视频点播事件回调post获取不到参数
    Nginx代理后服务端使用remote_addr获取真实IP
    记录:mac的浏览器访问任何域名、网址都跳转到本地127.0.0.1或固定网址
  • 原文地址:https://www.cnblogs.com/bin-gege/p/6909545.html
Copyright © 2011-2022 走看看