题目描述

给你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。

输入样例
  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

输出样例
  14
  19
  1050650

分析

乍一看,怎么又是背包。

再一看,woc,范围怎么这么大。

有一看,好像可以根据2的几次幂来分层,最后合并。

仔细一想,还不是要很大的空间和复杂度,而且还不会写。

再一想,千年等一回

最后放弃去网上找题解,结果发现有一个贪心,从一位与下一位的合并时,只考虑这一位1000以内的情况。

用dp[i][j]表示背包的容量已经占用了j*2^i+(w&((1<< i)-1))时的最大价值

先对于每一个i进行背包的合并,然后再考虑把每一位合并。

合并时,dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[i-1][2*k+((w>>(i-1) )&1)])

其中(2*k+((w>>(i-1))&1))可以通过倒推得到,用j*2^i+(w&((1<< i)-1))减去k*2^i+(w&((1<< i)-1))即可

upd 20191014

突然想到一种对dp转移式子的感性理解,第i位的k到第i-1位后就是k*2,而((w>>(i-1) )&1)就代表w在第i-1位是否有1

所以dp转移式子还可以优化成

dp[i][j]=max(dp[i][j],dp[i][j-k]+max(dp[i-1][2*k+((w>>(i-1) )&1)],dp[i-1][2*k]))

顺便把另一种写法也写了。。。。。。

推荐一个博客

好像物品可以一个一个加进去,时间上会有很大的优化,然而并不会写。

代码(不要在意那个O2)

#pragma GCC optimize (2)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,cnt,i,j,k,w,val,f[][];
int main()
{
while(scanf("%d%d",&n,&m))
{
if(n==-&&m==-)return ;
memset(f,,sizeof f);
for(i=;i<=n;i++)
{
scanf("%d%d",&w,&val);
cnt=;while(w%==)w/=,cnt++;
for(j=;j>=w;j--)f[cnt][j]=max(f[cnt][j],f[cnt][j-w]+val);
}
int lim=;
for(i=m;i;i/=)lim++;lim--;
for(i=;i<=lim;i++)for(j=min(, m>>i);j>=;j--)for(k=;k<=j;k++)
f[i][j]=max(f[i][j],f[i][j-k]+f[i-][min(,(k*)|((m>>(i-))&))]);
printf("%d\n",f[lim][]);
}
}
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long f[][];
int n,m,st[][][];
int main()
{
while(scanf("%d%d",&n,&m))
{
if(n==-&&m==-)return ;
memset(f,,sizeof f);memset(st,,sizeof st);
for(int i=,a,b,cnt;i<=n;i++)
{
scanf("%d%d",&a,&b);cnt=;
while(a%==)a/=,cnt++;
st[cnt][++st[cnt][][]][]=a;st[cnt][st[cnt][][]][]=b;
}
int lim=;for(int i=m/;i;i/=)lim++;
for(int i=;i<=lim;i++)
{
if(i)for(int j=;j<=;j++)f[i][j]=f[i-][min(,(j<<)|((m>>(i-))&))];
for(int j=;j<=st[i][][];j++)for(int k=min(m>>i,);k>=st[i][j][];k--)
f[i][k]=max(f[i][k],f[i][k-st[i][j][]]+st[i][j][]);
}
printf("%lld\n",f[lim][]);
}
}

【洛谷】P3188 [HNOI2007]梦幻岛宝珠的更多相关文章

  1. P3188 [HNOI2007]梦幻岛宝珠

    传送门 注意到 $a,b$ 不大 考虑对每一个 $a*2^b$ 的 $b$ 分别背包 设 $f[i][j]$ 表示只考虑 $b=i$ 的物品时,容量为 $j= \sum a$ 的最大价值 这个就是普通 ...

  2. [BZOJ 1190][HNOI2007]梦幻岛宝珠

    1190: [HNOI2007]梦幻岛宝珠 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1057  Solved: 611[Submit][Stat ...

  3. 【BZOJ1190】[HNOI2007]梦幻岛宝珠 分层背包DP

    [BZOJ1190][HNOI2007]梦幻岛宝珠 Description 给你N颗宝石,每颗宝石都有重量和价值.要你从这些宝石中选取一些宝石,保证总重量不超过W,且总价值最大为,并输出最大的总价值. ...

  4. BZOJ 1190 [HNOI2007]梦幻岛宝珠(背包)

    1190: [HNOI2007]梦幻岛宝珠 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1385  Solved: 798[Submit][Stat ...

  5. luogu 3188 [HNOI2007]梦幻岛宝珠

    LINK:梦幻岛宝珠 时隔多日 我再次挑战这道题.还是以失败告终. 我觉得这一道背包真的有点难度 这是一个数量较少 但是价值和体积较大的背包. 通常的01背包 要不就是体积小 要么是价值小 但这道题给 ...

  6. 【题解】 bzoj1190: [HNOI2007]梦幻岛宝珠 (动态规划)

    bzoj1190,懒得复制,戳我戳我 Solution: 这道题其实是一个背包(分组背包),但是由于数字比较大,就要重新构造dp式子.啃了三天才懂. \(dp[i][j]\)表示背包容积为\(j*2^ ...

  7. 洛谷 P3190 [HNOI2007]神奇游乐园 解题报告

    P3190 [HNOI2007]神奇游乐园 Description 给你一个 \(m * n\) 的矩阵,每个矩阵内有个权值\(V(i,j)\) (可能为负数),要求找一条回路,使得每个点最多经过一次 ...

  8. 1190: [HNOI2007]梦幻岛宝珠 - BZOJ

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

  9. [HNOI2007]梦幻岛宝珠(背包)

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

随机推荐

  1. Vue使用QRCode.js生成二维码

    1.安装qrcode npm install qrcode 2.组件中引入qrcode import QRCode from 'qrcode' 3.html代码 <div><span ...

  2. 使用vue脚手架搭建项目并将px自动转化为rem

    一.安装node.js环境 二.node.js安装完成后使用npm安装vue脚手架vue-cli和安装webpack,我这里用cnpm cnpm i @vue/cli -g //全局安装脚手架3.0 ...

  3. Jwt Token 令牌

    /* 采用JWT的生成TOKEN,及APP登录Token的生成和解析 */ public class JwtTokenUtil { /** * token秘钥 */ public static fin ...

  4. vscode编辑器中文乱码问题

    设置配置自动格式化: "[javascriptreact]": { "editor.defaultFormatter": "esbenp.pretti ...

  5. 学习python的日常

    今天是开始正式接触python语言的第一天,然后来自前辈的知道开始了在学习过程当中用博客来记录自己的学习历程,以供自己更快地掌握这门编程语言. 大概的总结一下的话,还是按照我的编程的习惯,要学写代码, ...

  6. 系统调用IO和标准IO

    目录 1. 系统调用IO(无缓冲IO) 系统调用 常用系统调用IO函数 open close read write lseek ioctl 2. 标准IO(带缓冲IO) 概述 缓冲与冲洗 常用标准IO ...

  7. Python_变量作用域

    1.变量作用域: def get_apple(name,*b): global totalCount totalCount=0 for num in b: print('............... ...

  8. django框架介绍安装-自写框架

    原文链接:https://www.cnblogs.com/maple-shaw/p/8862330.html Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户 ...

  9. (Linux基础学习)第一章:科普和Linux系统安装

    第一章:科普和Linux系统安装 第1节:操作系统介绍OS:Operating System,通用目的的软件程序硬件驱动进程管理内存管理网络管理安全管理文件管理OS分类:服务器OS:RHEL,Cent ...

  10. 使用Eclipse Memory Analyzer进行内存泄漏分析

    一.准备工作 1)工具下载: http://www.eclipse.org/mat/downloads.php 可以选择eclipse插件的方式安装 http://download.eclipse.o ...