今天在这里说一下多重背包问题 对

之前一直没有怎么彻底理解

首先多重背包是什么?这里就不做过多的赘述了

朴素的多重背包的复杂度是\(O(n*m*\sum s[i])\),其中\(s[i]\)是每一件物品的数量

  1. for (int i=1;i<=n;i++)
  2. for (int k=1;k<=s[i];k++)
  3. for (int j=m;j>=k*c[i];j--)
  4. dp[j]=max(dp[j],dp[j-k*c[i]]+k*w[i]);

但大多数题目,这种复杂度是不能允许的

那么我们考虑优化

首先我们考虑,怎么样快速表示\(1~n\)中所有的数呢?

二进制!

打个比方\(n=6\),那么我们就只需要1 2 3就能构成所有的数

1=1

2=2

3=3

4=1+3

5=2+3

6=1+2+3

对于一个数n,我们只需要从小开始不停用n减去2的幂次方,若n大于0,则当前的二的幂次方合法,最后我们将合法的二的幂次方和最后的余数分别看成一个新的物品去做背包,就能表示出所有的\(1~n\)的数(可以理解为,小于n的数的二进制,一定不会比n大,那么构成n的这些二进制位,一定是够用的)

那么我们只需要对\(s[i]\)进行二进制拆分,然后把他们看成一个物品

直接上代码

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<queue>
  7. using namespace std;
  8. inline int read()
  9. {
  10. int x=0,f=1;char ch=getchar();
  11. while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  12. while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  13. return x*f;
  14. }
  15. const int maxn = 2e5+1e2;
  16. int f[maxn];
  17. int n,m;
  18. int c[maxn],w[maxn];
  19. int tmp ;
  20. int main()
  21. {
  22. n=read(),m=read();
  23. for (int i=1;i<=n;i++)
  24. {
  25. int y=read(),z=read(),x=read();
  26. int inv = 1;
  27. while (x)
  28. {
  29. inv=min(inv,x);
  30. w[++tmp]=inv*y;
  31. c[tmp]=inv*z;
  32. x-=inv;
  33. inv<<=1;
  34. }
  35. }
  36. //for (int i=1;i<=tmp;i++) co
  37. memset(f,0xdf,sizeof(f));
  38. f[0]=0;
  39. for (int i=1;i<=tmp;i++)
  40. {
  41. for (int j=m;j>=c[i];j--)
  42. {
  43. f[j]=max(f[j],f[j-c[i]]+w[i]);
  44. }
  45. }
  46. int ans=-1e9;
  47. for (int i=1;i<=m;i++) ans=max(ans,f[i]);
  48. cout<<ans;
  49. return 0;
  50. }

QwQ 二进制优化的复杂度是\(O(nlogn\times m)\)

然而,我们可以用单调队列做到\(O(nm)\)的(虽然据说常数很大)

这里比较懒,直接放一个dalao的博客了

我就写几点自己的理解吧:

首先,我们是枚举体积的余数和倍数,然后转移

维护单调队列的时候,一定要注意维护队首元素过期

虽然我也不知到这种算法的正确性,不过它运用的思路就是把同样的余数\(m'\),放到一起考虑对

直接上代码

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<cstring>
  5. #include<cmath>
  6. using namespace std;
  7. inline int read()
  8. {
  9. int x=0,f=1;char ch=getchar();
  10. while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
  11. while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  12. return x*f;
  13. }
  14. const int maxn = 2e5+1e2;
  15. int q[maxn],t[maxn];
  16. int head=1,tail=0;
  17. void push(int x,int pos,int p)
  18. {
  19. while (head<=tail && x>=q[tail])
  20. q[tail]=0,t[tail--]=0;
  21. q[++tail]=x;
  22. t[tail]=pos;
  23. while (head<tail && t[head]<pos-p) head++;
  24. }
  25. int c[maxn],w[maxn],s[maxn];
  26. int n,m;
  27. int f[110][maxn];
  28. int main()
  29. {
  30. n=read(),m=read();
  31. for (int i=1;i<=n;i++) w[i]=read(),c[i]=read(),s[i]=read();
  32. for (int i=1;i<=n;i++)
  33. {
  34. //if (c[i]==0) while (1);
  35. int kk = m/c[i]; //
  36. int num = min(s[i],kk); //最多能放多少个
  37. for (int j=0;j<c[i];j++) //枚举余数
  38. {
  39. head=1,tail=0;
  40. int ymh = (m-j)/c[i];
  41. for (int k=0;k<=ymh;k++)
  42. {
  43. push(f[i-1][j+k*c[i]]-k*w[i],k,num);
  44. f[i][j+k*c[i]]=max(f[i][j+k*c[i]],q[head]+k*w[i]);
  45. }
  46. }
  47. }
  48. int ans=-1e9;
  49. //for (int i=0;i<=m;i++) ans=max(ans,f[n][i]);
  50. for (int i=1;i<=n;i++)
  51. for (int j=1;j<=m;j++) ans=max(ans,f[i][j]);
  52. cout<<ans;
  53. return 0;
  54. }

回归本心QwQ背包问题luogu1776的更多相关文章

  1. 【洛谷p1605】迷宫

    (还记得我昨天大概没人看到的博客(我删辽)吗qwq,2019.4.14下午交的qwq 那篇博客大致内容就是:我提交楼上这道题,交了好久好久好久好久 现在我告诉你,那次评测还N/A着呢qwq) tqlq ...

  2. Java 的几种版本

    1. Java ME Java ME(Java 2 Micro Edition),是为机顶盒.移动电话和PDA之类嵌入式消费电子设备提供的Java语言平台,包括虚拟机和一系列标准化的Java API. ...

  3. 你在开发过程中使用Git Rebase还是Git Merge?

    摘要:在git里面经常的一个争论是到底用rebase还是用merge? 1. 痛苦吗?代码历史中的迷失羔羊 我们先来看一个真实的代码提交历史图形化截图: 图片源自 https://storage.kr ...

  4. dp小结|背包问题

    1.先放上0-1背包模板 二维数组 for(int i=1;i<=n;i++)//枚举 物品 for(int j=1;j<=V;j++)//枚举体积 //这个位置是可以正序枚举的. qwq ...

  5. 决策树的剪枝,分类回归树CART

    决策树的剪枝 决策树为什么要剪枝?原因就是避免决策树“过拟合”样本.前面的算法生成的决策树非常的详细而庞大,每个属性都被详细地加以考虑,决策树的树叶节点所覆盖的训练样本都是“纯”的.因此用这个决策树来 ...

  6. 【模板】各种背包问题&讲解

                                        背包问题集合 一般来说,动态规划(DP)都是初学者最难闯过的一关,而在这里详细解说动态规划的一种经典题型:背包问题. 这里介绍的 ...

  7. 神经网络、logistic回归等分类算法简单实现

    最近在github上看到一个很有趣的项目,通过文本训练可以让计算机写出特定风格的文章,有人就专门写了一个小项目生成汪峰风格的歌词.看完后有一些自己的小想法,也想做一个玩儿一玩儿.用到的原理是深度学习里 ...

  8. SVM分类与回归

    SVM(支撑向量机模型)是二(多)分类问题中经常使用的方法,思想比较简单,但是具体实现与求解细节对工程人员来说比较复杂,如需了解SVM的入门知识和中级进阶可点此下载.本文从应用的角度出发,使用Libs ...

  9. 原创:去繁存简,回归本源:微信小程序公开课信息分析《一》

    以前我开过一些帖子,我们内部也做过一些讨论,我们从张小龙的碎屏图中 ,发现了重要讯息: 1:微信支付将成为重要场景: 2:这些应用与春节关系不小,很多应用在春节时,有重要的场景开启可能性: 3:春节是 ...

随机推荐

  1. linux centos7 tail

    2021-08-30 # 不指定行数,默认显示 10 行 # 显示 /var/log/crond 后100行 taile -100 /var/log/crond # 动态显示 /var/log/cro ...

  2. Shell中常用的语句

    exit 完全中断脚本的执行 break 中断脚本的循环,但是会执行循环外的语句 continue 跳出本次循环,进行下一次循环 进一步了解三者的区别,有如下实验: 执行该脚本: 脚本正常运行情况: ...

  3. Java基础之类加载器

    Java类加载器是用户程序和JVM虚拟机之间的桥梁,在Java程序中起了至关重要的作用,理解它有利于我们写出更优雅的程序.本文首先介绍了Java虚拟机加载程序的过程,简述了Java类加载器的加载方式( ...

  4. DPDK应用示例指南简介(汇总)

    DPDK应用示例指南简介 <DPDK示例>系列文章主要是学习.记录.翻译DPDK官方示例文档.为了更好地理解和学习DPDK, 特通过对源码中的经典示例进行整理,供大家学习.交流和讨论. A ...

  5. Identity用户管理入门六(判断是否登录)

    目前用户管理的增删改查及登录功能已经全部实现,但存在一个问题,登录后要取消登录按钮显示退出按钮,未登录应该有注册按钮,现实现过程如下 一.Startup.cs中增加服务 app.UseAuthenti ...

  6. 全局CSS样式表

    看api手册使用即可 1.按钮和图片 2.表格.表单 表单的lable作用就是点击前面的文字可以聚焦到对应的输入框中

  7. Spring Cloud Eureka 之开发笔记

    Eureka客户端 -- 接口 com.netflix.discovery public interface EurekaClient /*常用方法*/ // 获取某个应用 Application g ...

  8. XSS注入

    XSS 原理: 程序对输入和输出没有做合适的处理,导致"精心构造"的字符输出在前端时被浏览器当作有效代码解析执行从而产生危害. 分类 : 危害:存储型 > 反射型 > ...

  9. 使用git克隆仓库到本地报错:SSL certificate problem: unable to get local issuer certificate

    第一次使用Git工具克隆仓库,使用的是HTTPS链接,失败了.发现是因为通过HTTPS访问时,如果服务器上的SSL证书未经过第三方机构认证,Git就会报错. 解决方法:通过命令关闭验证 git con ...

  10. [CSP-J2020] 优秀的拆分

    [CSP-J2020] 优秀的拆分 难度:普及- 题目描述 一般来说,一个正整数可以拆分成若干个正整数的和. 例如,1=1,10=1+2+3+4 等.对于正整数 n 的一种特定拆分,我们称它为&quo ...