当前位置: 首页 > news >正文

多重背包--二进制优化

问题描述:

有N种物品和一个容量为V的背包。第 i 种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。


问题分析:

1.初步:

多重背包最朴素的思想就是将所有的物品(不管同不同一类)都看不同的种类,进行01背包的求解。另也可以看做完全背包的变形:第 i 种物品可以取0件、取1件……取n[i]件。

for(int i = 1; i <= N; ++i)
{
	for(int j = V; j >= c[i]; --j)
	{
		for(int k = 0; k <= n[i] && c[i]*k <= j; ++k)
		{
			dp[j] = max(dp[j], dp[j-k*c[i]] + k*w[i]);
		}
	}
}


2.优化:

很明显朴素的做法过于暴力,是个题都会卡这个时间或者空间的,所以需要进行二进制优化。

二进制思想:

假设有 1000 个苹果,现在要取n个苹果,如何取?朴素的做法应该是将苹果一个一个拿出来,直到n个苹果被取出来。
再假设有 1000 个苹果和10只箱子,利用箱子进行某些预工作,然后如何快速的取出n个苹果呢?So..可以在每个箱子中放 2^i (i<=0<=n)个苹果,也就是 1、2、4、8、16、32、64、128、256、489(n减完之前的数之后不足 2^i,取最后剩余的数),相当于把十进制的数用二进制来表示,取任意n个苹果时,只要推出几只箱子就可以了。

再次分析:

只看上面是不好理解的,比如:7的二进制 7 = 111, 它可以分解成 001, 010, 100. 这三个数可以组合成任意小于等于 7 的数,而且每种组合都会得到不同的数。再比如,13 = 1101, 则分解为 0001, 0010, 0100, 0110. 前三个数字可以组合成 7 以内任意一个数,每个数再加上0110(= 6) 之后可以组合成任意一个大于等于 6 小于等于 13 的数,所以依然能组成任意小于等于 13 的数,很明显 6,7 会多重复 1 次,但对于求解背包问题是没有影响的,基于这种思想把一种多件物品转换为,多件一种物品,然后用01背包求解即可。
下面证明一下为什么有重复没有影响的正确性
不正确可能产生的原因就是将重复的多加一次,比如 7+7=14 就可能造成错误,但是分析一下其实是不可能出现的,因为假如第一个 7 是由 0001+0010+0100 得到的,那么第二个 7 就需要用到 0110+0001,但 0001 只能出现一次嘛,所以不会形成这种错误的,其它的可能错误操作也能由这种解释进行否定,从而验证了正确性。

代码1

int num[maxn][2], dp[maxn];
int N, V, c, w, n, tot;
memset(dp, 0, sizeof dp);
cin >> V >> N; tot = 1;
for(int i = 1; i <= N; ++i)
{
	cin >> c >> w >> n;
	for(int k = 1; k < n; k<<=1)//左移求下一个所需二进制数 
	{
		num[tot][0] = k*c;
		num[tot++][1] = k*w;
		n -= k;
	}
	num[tot][0] = n*c;
	num[tot++][1] = n*w;
}
for(int i = 1; i < tot; ++i)
{
	for(int j = V; j >= num[i][0]; --j)
		dp[j] = max(dp[j], dp[j-num[i][0]]+num[i][1]);
}

代码2

int num[maxn][2], dp[maxn];
int N, V, c, w, n, t;
memset(dp, 0, sizeof dp);
cin >> V >> N;
for(int i = 1; i <= N; ++i)
{
	cin >> c >> w >> n;
	for(int k = 1; k < n; k<<=1) 
	{
		for(int j = V; j >= k*c; --j)
			dp[j] = max(dp[j], dp[j-k*c]+k*w);
		n -= k;
	}
	for(int j = V; j >= n*c; --j)
		dp[j] = max(dp[j], dp[j-n*c]+n*w);
}

继续加油~

相关文章:

  • JS高级程序设计2nd部分知识要点2
  • HDU-4549(矩阵快速幂+欧拉定理)
  • xcode Aborting commit: '~/Pods' remains in tree-conflict 错误的解决办法
  • 网络流之最大流(FF, EK, Dinic, SAP)
  • QDU-ycb的ACM进阶之路(多重背包做法)
  • 2017年第0届浙江工业大学之江学院程序设计竞赛决赛—B qwb与矩阵
  • F5 LTM 在SIP消息负载均衡中存在的问题
  • 2017年第0届浙江工业大学之江学院程序设计竞赛决赛—D qwb与神奇的序列
  • 我所爱的世界
  • 2017年第0届浙江工业大学之江学院程序设计竞赛决赛—J qwb又偷懒了
  • 字符串处理文章outline
  • 2017年第0届浙江工业大学之江学院程序设计竞赛决赛—K qwb与小数
  • java内存管理机制
  • 网络流-割的概念以及定理
  • HDU 3533 Escape
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • Angular Elements 及其运作原理
  • cookie和session
  • Essential Studio for ASP.NET Web Forms 2017 v2,新增自定义树形网格工具栏
  • Fundebug计费标准解释:事件数是如何定义的?
  • Git同步原始仓库到Fork仓库中
  • JDK 6和JDK 7中的substring()方法
  • Mithril.js 入门介绍
  • storm drpc实例
  • underscore源码剖析之整体架构
  • 浮动相关
  • 那些年我们用过的显示性能指标
  • 如何在GitHub上创建个人博客
  • 使用权重正则化较少模型过拟合
  • 想晋级高级工程师只知道表面是不够的!Git内部原理介绍
  • 【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路
  • 测评:对于写作的人来说,Markdown是你最好的朋友 ...
  • 进程与线程(三)——进程/线程间通信
  • ​Kaggle X光肺炎检测比赛第二名方案解析 | CVPR 2020 Workshop
  • ![CDATA[ ]] 是什么东东
  • #includecmath
  • #微信小程序:微信小程序常见的配置传值
  • $con= MySQL有关填空题_2015年计算机二级考试《MySQL》提高练习题(10)
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (Spark3.2.0)Spark SQL 初探: 使用大数据分析2000万KF数据
  • (差分)胡桃爱原石
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (附源码)php投票系统 毕业设计 121500
  • (附源码)计算机毕业设计SSM智慧停车系统
  • (考研湖科大教书匠计算机网络)第一章概述-第五节1:计算机网络体系结构之分层思想和举例
  • (强烈推荐)移动端音视频从零到上手(上)
  • (三十五)大数据实战——Superset可视化平台搭建
  • .NET 2.0中新增的一些TryGet,TryParse等方法
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .net wcf memory gates checking failed
  • .NetCore部署微服务(二)
  • .net程序集学习心得
  • .NET中的Exception处理(C#)
  • .pings勒索病毒的威胁:如何应对.pings勒索病毒的突袭?
  • @ 代码随想录算法训练营第8周(C语言)|Day53(动态规划)