zoukankan      html  css  js  c++  java
  • 题解报告——梦幻岛的珠宝

    传送门

    题目描述

    给你N颗宝石,每颗宝石都有重量和价值。要你从这些宝石中选取一些宝石,保证总重量不超过W,且总价值最大为,并输出最大的总价值。数据范围:N<=100;W<=2^30,并且保证每颗宝石的重量符合a*2^b(a<=10;b<=30)

    输入输出格式

    输入格式:

    输入文件中包含多组数据。每组数据的格式如下:第一行是两个正整数n和W,1<=n<=100,1<=W<=2^30,分别表示宝石的数目和最多能带走的宝石重量。接下来的n行,每行有两个正整数weighti和valuei,1<=weighti<=2^30, 0<=valuei<=2^30,分别表示第i颗宝石的重量和价值,且保证weighti能写成a*2^b(1<=a<=10,0<=b<=30)的形式。同一行的两个正整数之间用空格隔开。最后一组数据的后面有两个-1,表示文件的结束。这两个-1并不代表一组数据,你不需对这组数据输出结果。并且输入文件中数据的组数不超过20。

    输出格式:

    对于输入的每组数据,输出一个整数C,表示小P最多能带走的宝石的总价值。每个结果整数C单独占一行,且保证C不会超过2^30。

    输入输出样例

    输入样例#1:
    4 10
    8 9
    5 8
    4 6
    2 5
    4 13
    8 9
    5 8
    4 6
    2 5
    16 75594681
    393216 5533
    2 77
    32768 467
    29360128 407840
    112 68
    24576 372
    768 60
    33554432 466099
    16384 318
    33554432 466090
    2048 111
    24576 350
    9216 216
    12582912 174768
    16384 295
    1024 76
    -1 -1
    输出样例#1:
    14
    19
    1050650

    【思路分析】
    首先看到这道题我们就会发现这是一个背包,然后看到数据范围发现这显然不是很资瓷背包的操作啊,最后发现正解其实还真的就是背包。
    这里我们使用的不是普通的背包,美其名曰分层背包。
    看到了每个物品的重量都可以表示为j*2^i,我们就可以按进制分层,每一层都是i相同的,然后我们先层内做一个普通的背包,然后再跨层做背包。
    用dp[i][j]表示第i层系数为j,也就是j*2^i重量的最大价值,然后根据j来进行层内dp。
    注意我们只需要维护最大价值即可,所以不用像平时做背包时那样判断当前体积出现过没有,直接加上新增体积即可。
    然后发现这样做背包有个妙妙的性质那就是背包中体积越大的地方价值也越大,可以自行脑补。
    然后就做跨层背包,由于上面的性质,我们设dp[i][j]表示j*2^i+w&((1<<i)-1)的体积,然后转移即可

    【代码实现】
     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cctype>
     4 #include<cstring>
     5 using namespace std;
     6 typedef long long ll;
     7 void read(int &v)
     8 {
     9     int f;char ch;
    10     while(!isdigit(ch=getchar())&&ch!='-'); ch=='-'?(v=0,f=-1):(v=ch-'0',f=1);
    11     while(isdigit(ch=getchar())) v=v*10+ch-'0';v=v*f;
    12 }
    13 const int N=35;
    14 int n,m,val,exp;
    15 ll dp[N][1005];
    16 int main()
    17 {
    18     while(1)
    19     {
    20         memset(dp,0,sizeof(dp));
    21         read(n),read(m);
    22         if(n==-1&&m==-1) break;
    23         for(int i=1;i<=n;i++)
    24         {
    25             read(exp),read(val);
    26             int cnt=0;
    27             while(exp%2==0) exp=exp>>1,cnt++;
    28             for(int j=500;j>=exp;j--) dp[cnt][j]=max(dp[cnt][j],dp[cnt][j-exp]+val);
    29         }
    30         int top=0;
    31         for(int i=m;i;i>>=1) top++;top--;
    32         for(int i=1;i<=top;i++)
    33         for(int j=500;j>=0;j--)
    34         for(int k=0;k<=j;k++)
    35         dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[i-1][min(500,(2*k)|(m>>(i-1))&1)]);
    36         printf("%lld
    ",dp[top][1]);
    37     }
    38     return 0;
    39 }
    
    
     
  • 相关阅读:
    Git 标签管理
    Git 分支管理
    HTTP 400 错误 编译器错误消息: CS0016
    使用DOS指修改文件名
    跨服务器连接数据库
    SharePoint 2013 页面访问,Url中间多一段"_layouts/15/start.aspx#"
    SharePoint 2013 搜索高级配置
    sharepoint 2013 创建母版页
    SharePoint 2013上传AI格式文件,再次下载后变成了PS格式文件
    SharePoint 2013 配置启用搜索服务
  • 原文地址:https://www.cnblogs.com/genius777/p/9571511.html
Copyright © 2011-2022 走看看