背包九讲 修正版
- 格式:docx
- 大小:39.04 KB
- 文档页数:11
ACM暑期集训报告院系:专业:年级:学号:姓名:日期:西南交通大学目录目录 (1)第1章动态规划(dp) (2)1.1 简介 (2)1.2 教师内容 (5)1.3 基本dp——背包问题 (6)1.4若干经典dp及常见优化 (9)1.5类似题目 (10)参考文献 (31)附录1 暑期集训心得体会 (31)第1章动态规划(dp)(标题采用2号黑体居中,下空1行)1.1 简介(标题采用四号黑体,正文内容采用小四号字体,1.5倍行距)在解决问题的时候我们经常遇到这种问题:在多种方式的操作下我们如何得到一个最优的方式让我们得到满意的结果。
这时候我们大多人的思想就是贪心。
不错贪心确实是一个不错的算法,首先他简单容易想到,我们在操作起来也比较容易。
现在我推荐几道我们oj上的贪心算法的题:soj1562药品运输soj1585 Climbing mountain。
为了引入动归算法我先拿药品运输这道题简单说一下贪心算法。
示例1:药品运输(题目采用小四号Times New Roman字体)Description5.12大地震后,某灾区急需一批药品,现在有N种药品需要运往灾区,而我们的运输能力有限,现在仅有M辆运输车用来运输这批药品,已知不同的药品对灾区具有不同的作用(“作用”用一个整数表示其大小),不同的药品需要的运输力(必要的车辆运载力)不同,而不同的车辆也具有不同的运输力。
同时,我们希望不同的药品用不同的车辆来运输(避免发生混淆)。
现在请你帮忙设计一方案,来使得运往灾区的药品对灾区的作用最大。
Input第一行包含一个整数T,表示需要处理的测试数据组数。
每一组第一行包括两个整数N,M,分别表示药品总数,及车辆总数。
接着第二行包含N个整数(pi<=10000),分别表示每种药品的作用。
接着第三行包含N个整数,分别表示每种药品必须得运载力(wi<=1000)。
接着第四行包含M个整数,表示每辆车的运输力(c<=1000);(T<=10; N,M<=1000)Output输出包括T行,每行仅一个整数,表示最大的作用值。
第九讲平均数问题例1 一辆轿车在一次旅行中用1.5小时行了80千米,后因交通堵塞停了30分钟,然后又用2小时行了100千米,这辆车在整个过程中的平均速度是________。
例2 一超市中,德芙巧克力每千克78元,台尚巧克力每千克43.8元,徐福记巧克力每千克45.8元,现将12千克的德芙巧克力,30千克的台尚巧克力,25千克的徐福记巧克力混合在一起卖。
问:混合后的巧克力每千克至少卖多少钱才合适?例3 空间站上的5位宇航员轮流值班和休息,值班岗位有2人。
在60小时里,平均每位宇航员休息了________小时。
例4 在99个连续的自然数中,最大的数是最小的数的25.5倍,那么这99个自然数的平均数是________.例5 小明计算1~2006这2006个连续整数的平均数。
在求这2006个数的和时,他少算了其中的一个数,但他仍按2006个数计算平均数,结果求出的数比应求得的数小1,小明求和时漏掉的数是________。
例.6 五(1)班男生的平均身高是149cm,女生的平均身高是144cm,全班同学的平均身高是147cm,则五(1)班的男生人数是女生人数的_______倍。
例7 有四个数,任取其中三个数相加,得到四个不同的和,70,80,73,77,则这四个数分别为_________________。
例8 一次数学竞赛,满分是100分,某小组的8位同学得分都是整数,并且互不相同,已知这8位同学的平均分是90分,其中一位同学仅得62分,那么第五名至少得________分。
1.某学生计算6个数的平均数,最后一步应除以6,但是他将“÷”错写成“×”,于是得错误答案1800,那么,正确答案是_______.2.一辆汽车用全速行驶了5分钟,又用半速行驶了6分钟,这11分钟的平均速度为800米/分。
这辆汽车全速每分钟行驶_______米。
3.商店把10千克水果糖和若干千克奶糖混合在一起得到每千克12元的什锦糖。
有这样一群人,他们放弃了朝九晚五的都市生活,将梦想装在背包里,走遍世界各地。
他们用身心去体会自然之美,用文字和照片记录行走的精彩。
他们不是传统意义上旅行者,也有别于普通背包客;他们是一群以旅行为职业的探索者。
央视网记者采访了知名旅行作家小鹏,作为职业“背包客”,他十分乐于分享他的旅行经历。
十年之前,张金鹏只是一个刚刚走出校门、怀揣着旅行梦想的大学毕业生;十年后,他已经是出版了四本畅销书的知名旅行作家“背包客小鹏”。
他用了十年的时间去行走,完成了从菜鸟背包客到作家的人生蜕变。
小鹏回忆说,第一次旅行去的是广西的阳朔。
这次旅行让他看到了另一种不同的生活方式--在如画的风景里,一杯咖啡、一把摇椅度过闲适的一天,这些画面激起了他旅行的梦想,去体味不同的人生。
最初,为了赚取旅费,三四年中小鹏先后换过八份工作。
后来,他发现旅行也可以赚钱,开始了为杂志社拍照、写稿的职业生涯。
随着积累,他的文章有了知名度,他开始写书,有了版税收入,也就可以继续旅行。
于是,小鹏成了职业旅行者。
他先后出版了《背包十年》、《莲花之上》、《我把欧洲塞进背包》及《我们为什么旅行》,这些作品都给他带来了相当可观的收入,支持他继续行走,走到更远的地方。
小鹏讲述了这些年最让他难忘的一次旅行,就是去阿拉斯加拍摄极光。
拍摄极光最好的时间是每年的9月底到3月底。
今年3月,小鹏到达阿拉斯加,为了等待极光,他在农舍里住了三个月。
由于极光是动态的画面,相机很难捕捉;而摄影机色彩表现力有不足,无法分辨天空与极光的色彩。
于是,小鹏只能将摄影机一秒钟的视频画面,切成24张画面;再用相机从同一时间、同一角度、同一参数拍摄下同样的画面,再将这24张清晰的照片,编辑成1秒钟的动态极光画面。
为了照片清晰,每一张照片都需要长时间曝光,大概一分钟时间,因此24张照片不可能连续完成。
为了这24张照片,他在零下30度的环境下等待了7天。
当然,最后这组珍贵的照片也为他带来不菲的收益。
NOIP复习资料(C++版)主编葫芦岛市一高中李思洋完成日期2012年8月27日……………………………………………………………最新资料推荐…………………………………………………前言有一天,我整理了NOIP的笔记,并收集了一些经典算法。
不过我感觉到笔记比较凌乱,并且有很多需要修改和补充的内容,于是我又搜集一些资料,包括一些经典习题,在几个月的时间内编写出了《NOIP复习资料》。
由于急于在假期之前打印出来并分发给同校同学(我们学校既没有竞赛班,又没有懂竞赛的老师。
我们大家都是自学党),《NOIP复习资料》有很多的错误,还有一些想收录而未收录的内容。
在“减负”的背景下,暑期放了四十多天的假。
于是我又有机会认真地修订《NOIP复习资料》。
我编写资料的目的有两个:总结我学过(包括没学会)的算法、数据结构等知识;与同学共享NOIP知识,同时使我和大家的RP++。
大家要清醒地认识到,《NOIP复习资料》页数多,是因为程序代码占了很大篇幅。
这里的内容只是信息学的皮毛。
对于我们来说,未来学习的路还很漫长。
基本假设作为自学党,大家应该具有以下知识和能力:①能够熟练地运用C++语言编写程序(或熟练地把C++语言“翻译”成Pascal语言);②能够阅读代码,理解代码含义,并尝试运用;③对各种算法和数据结构有一定了解,熟悉相关的概念;④学习了高中数学的算法、数列、计数原理,对初等数论有一些了解;⑤有较强的自学能力。
代码约定N、M、MAX、INF是事先定义好的常数(不会在代码中再次定义,除非代码是完整的程序)。
N、M、MAX 针对数据规模而言,比实际最大数据规模大;INF针对取值而言,是一个非常大,但又与int的最大值有一定差距的数,如100000000。
对于不同程序,数组下标的下限也是不同的,有的程序是0,有的程序是1。
阅读程序时要注意。
阅读顺序和方法没听说过NOIP,或对NOIP不甚了解的同学,应该先阅读附录E,以加强对竞赛的了解。
最值宝典第九讲:最大利润之背包问题背景介绍背包问题是一个经典的组合优化问题,常用于描述在有限容量的背包中装入物品,使得背包的总价值最大化的情况。
该问题在实际生活和工程领域有着广泛的应用。
问题描述假设有一个容量为C的背包,以及n个可以装入背包的物品。
每个物品有两个属性:重量wi和价值vi。
目标是选择一组物品装入背包,使得背包中物品的总重量不超过C,同时总价值最大化。
解决思路背包问题可以通过动态规划方法求解。
定义一个二维数组dp,其中dp[i][j]表示前i个物品在背包容量为j时的最大价值。
递推式如下:- 当i=0或j=0时,dp[i][j] = 0,表示背包容量为0或没有物品可选时,最大价值为0。
- 当j < wi时,dp[i][j] = dp[i-1][j],表示当前物品无法放入背包。
- 当j >= wi时,dp[i][j] = max(dp[i-1][j], dp[i-1][j-wi]+vi),表示当前物品可以放入背包,选择放入或不放入的最大价值。
算法实现根据上述思路,可以实现以下算法来解决背包问题:1. 初始化一个二维数组dp,大小为(n+1)*(C+1),并将所有元素初始化为0。
2. 使用两层循环遍历dp数组,计算其中每个元素的最大价值。
3. 返回dp[n][C],即为背包问题的最优解。
示例假设有5个物品,其重量和价值分别如下:物品1:重量2,价值6物品2:重量2,价值3物品3:重量3,价值5物品4:重量4,价值4物品5:重量5,价值6背包容量为10。
根据上述算法,求解最大利润问题可得到最优解为:最大利润为15,选择物品1、物品2和物品3放入背包。
总结背包问题是一个经典的组合优化问题,可以通过动态规划方法有效地求解。
通过定义动态规划数组和递推式,可以高效地求解背包问题,获取最大利润。
背包问题九讲目录第一讲 01背包问题第二讲完全背包问题第三讲多重背包问题第四讲混合三种背包问题第五讲二维费用的背包问题第六讲分组的背包问题第七讲有依赖的背包问题第八讲泛化物品第九讲背包问题问法的变化附:USACO中的背包问题前言本篇文章是我(dd_engi)正在进行中的一个雄心勃勃的写作计划的一部分,这个计划的内容是写作一份较为完善的NOIP难度的动态规划总结,名为《解动态规划题的基本思考方式》。
现在你看到的是这个写作计划最先发布的一部分。
背包问题是一个经典的动态规划模型。
它既简单形象容易理解,又在某种程度上能够揭示动态规划的本质,故不少教材都把它作为动态规划部分的第一道例题,我也将它放在我的写作计划的第一部分。
读本文最重要的是思考。
因为我的语言和写作方式向来不以易于理解为长,思路也偶有跳跃的地方,后面更有需要大量思考才能理解的比较抽象的内容。
更重要的是:不大量思考,绝对不可能学好动态规划这一信息学奥赛中最精致的部分。
你现在看到的是本文的1.0正式版。
我会长期维护这份文本,把大家的意见和建议融入其中,也会不断加入我在OI学习以及将来可能的ACM-ICPC的征程中得到的新的心得。
但目前本文还没有一个固定的发布页面,想了解本文是否有更新版本发布,可以在OIBH论坛中以“背包问题九讲”为关键字搜索贴子,每次比较重大的版本更新都会在这里发贴公布。
目录第一讲 01背包问题这是最基本的背包问题,每个物品最多只能放一次。
第二讲完全背包问题第二个基本的背包问题模型,每种物品可以放无限多次。
第三讲多重背包问题每种物品有一个固定的次数上限。
第四讲混合三种背包问题将前面三种简单的问题叠加成较复杂的问题。
第五讲二维费用的背包问题一个简单的常见扩展。
第六讲分组的背包问题一种题目类型,也是一个有用的模型。
后两节的基础。
第七讲有依赖的背包问题另一种给物品的选取加上限制的方法。
第八讲泛化物品我自己关于背包问题的思考成果,有一点抽象。
解体插入新书简介-回复本文题目为《解体插入新书简介》,主题为"中括号内的内容",下面将一步一步回答:[中括号内的内容]是一本新书的简介,详情如下。
首先,我们先来了解这本书的背景和出版信息。
[中括号内的内容]是一本新近出版的小说,由知名作家X撰写。
该书的出版日期为XXXX年X月X 日,在X出版社出版。
小说采用[X种文学风格],并获得了广泛的关注和好评。
接下来,我们来了解下这本书的主要内容和情节。
[中括号内的内容]是一部以[X主题/故事背景]为基础的小说。
故事发生在[X地点],描绘了主人公[X]的生活经历和成长历程。
故事涉及到[X的问题或挑战],主人公通过[X的方式或经历]来解决这些问题。
故事情节引人入胜,充满悬疑和紧张感,读者很容易被深深吸引。
作者巧妙地使用[X技巧]来传达故事的情感和主题,使读者产生共鸣。
在书中,作者通过[X手法]来塑造了丰富的人物形象。
主人公[X]是一个[X 的性格特点]的人物,读者可以从他的言谈举止和内心独白中感受到他的复杂性和真实性。
其他的次要角色也各自有着自己独特的特点和故事线,他们与主人公的关系和互动给整个故事增添了戏剧性和趣味性。
此外,作者深入描绘了[X背景/环境],使读者能够身临其境地感受到故事发生地的气氛和情景。
通过对[X的描写],读者可以更好地理解故事中人物的动机和行为,加深对故事的理解和共鸣。
作者还运用了[X描写手法]来给读者带来视听上的享受。
值得一提的是,[中括号内的内容]也探讨了一些现实生活中的[X议题/社会问题]。
作者巧妙地将这些议题融入到故事中,通过角色和情节来传达对于这些问题的思考和观点。
读者在阅读的过程中不仅能够享受故事本身的乐趣,还能够思考和反思当代社会的一些现象和问题。
最后,这本书除了故事本身的吸引力以外,还有着[X特点/亮点],使它与其他作品相比更加独特。
这些特点可能包括书中的[X元素]、作者的独特写作风格或者对于某一主题的独到见解等等。
9章逐节最简单解释
嘿,朋友!你知道啥是 9 章逐节最简单解释不?咱就这么说吧,这
就好比是你在走一条路。
每一章就是一段路,每一节呢,就是这段路
上的一个个小步子。
(就像你爬山,每一个台阶都是向山顶迈进的一
小步。
)
比如说,第一章可能是个开头,就像你要开启一场冒险,你得先迈
出第一步吧。
(就好像你决定去学游泳,第一步就是换上泳衣,对吧?)然后每一节呢,就是在这个开头的基础上,一点点深入,一点
点展开。
第二章可能就是遇到困难啦,哎呀,这可咋办呢?(这不就跟你玩
游戏遇到难关一样嘛!)每一节就是你想各种办法去克服这个困难的
过程。
再往后,第三章可能是有了新发现,哇塞,原来还能这样!(好比
你突然发现了一个隐藏的宝藏地点。
)
这么一章一章,一节一节地走下去,你就会越来越明白整个事情的
来龙去脉啦!你想想看,要是没有这一节一节的详细解释,那得多迷
糊呀!(就像你做饭没有菜谱,那不是瞎搞嘛!)
咱再换个例子,9 章逐节就像是一部电影。
每一章就是一个大的情
节段落,每一节就是里面的一个个小场景。
(就像一部精彩的动作片,有紧张刺激的追逐,也有温情的对话。
)
9 章逐节的解释就是让你清楚地知道每个情节是怎么发展的,每个场景有啥意义。
(不然你看完电影都不知道到底讲了啥,那多可惜呀!)
我觉得 9 章逐节最简单解释真的超级重要啊!它能让我们不迷糊,能清楚地知道事情的全貌,能深入地理解每个细节。
这就像是给我们一把钥匙,打开知识的大门,让我们能在里面尽情探索!你说是不是呢?。
背包九讲P01: 01背包问题题目有N件物品和一个容量为V的背包。
第i件物品的费用是c[i],价值是w[i]。
求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
基本思路这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。
用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。
则其状态转移方程便是:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}。
这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。
所以有必要将它详细解释一下:“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。
如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”;如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。
注意f[i][v]有意义当且仅当存在一个前i件物品的子集,其费用总和为v。
所以按照这个方程递推完毕后,最终的答案并不一定是f[N] [V],而是f[N][0..V]的最大值。
如果将状态的定义中的“恰”字去掉,在转移方程中就要再加入一项f[i][v-1],这样就可以保证f[N] [V]就是最后的答案。
至于为什么这样就可以,由你自己来体会了。
优化空间复杂度以上方法的时间和空间复杂度均为O(N*V),其中时间复杂度基本已经不能再优化了,但空间复杂度却可以优化到O(V)。
先考虑上面讲的基本思路如何实现,肯定是有一个主循环i=1..N,每次算出来二维数组f[i][0..V]的所有值。
那么,如果只用一个数组f [0..V],能不能保证第i次循环结束后f[v]中表示的就是我们定义的状态f[i][v]呢?f[i][v]是由f[i-1][v]和f[i-1] [v-c[i]]两个子问题递推而来,能否保证在推f[i][v]时(也即在第i次主循环中推f[v]时)能够得到f[i-1][v]和f[i-1][v -c[i]]的值呢?事实上,这要求在每次主循环中我们以v=V..0的顺序推f[v],这样才能保证推f[v]时f[v-c[i]]保存的是状态f[i -1][v-c[i]]的值。
伪代码如下:fori=1..Nfor v=V..0f[v]=max{f[v],f[v-c[i]]+w[i]};其中的f[v]=max{f[v],f[v-c[i]]}一句恰就相当于我们的转移方程f[i][v]=max{f[i-1][v],f[i- 1][v-c[i]]},因为现在的f[v-c[i]]就相当于原来的f[i-1][v-c[i]]。
如果将v的循环顺序从上面的逆序改成顺序的话,那么则成了f[i][v]由f[i][v-c[i]]推知,与本题意不符,但它却是另一个重要的背包问题P02最简捷的解决方案,故学习只用一维数组解01背包问题是十分必要的。
总结01背包问题是最基本的背包问题,它包含了背包问题中设计状态、方程的最基本思想,另外,别的类型的背包问题往往也可以转换成01背包问题求解。
故一定要仔细体会上面基本思路的得出方法,状态转移方程的意义,以及最后怎样优化的空间复杂度。
P02: 完全背包问题题目有N种物品和一个容量为V的背包,每种物品都有无限件可用。
第i种物品的费用是c[i],价值是w[i]。
求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
基本思路这个问题非常类似于01背包问题,所不同的是每种物品有无限件。
也就是从每种物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取0件、取1件、取2件……等很多种。
如果仍然按照解01背包时的思路,令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值。
仍然可以按照每种物品不同的策略写出状态转移方程,像这样:f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<= v}。
这跟01背包问题一样有O(N*V)个状态需要求解,但求解每个状态的时间则不是常数了,求解状态f[i][v]的时间是O(v/c[i]),总的复杂度是超过O(VN)的。
将01背包问题的基本思路加以改进,得到了这样一个清晰的方法。
这说明01背包问题的方程的确是很重要,可以推及其它类型的背包问题。
但我们还是试图改进这个复杂度。
一个简单有效的优化完全背包问题有一个很简单有效的优化,是这样的:若两件物品i、j满足c[i]<=c[j]且w[i]>=w[j],则将物品j去掉,不用考虑。
这个优化的正确性显然:任何情况下都可将价值小费用高得j换成物美价廉的i,得到至少不会更差的方案。
对于随机生成的数据,这个方法往往会大大减少物品的件数,从而加快速度。
然而这个并不能改善最坏情况的复杂度,因为有可能特别设计的数据可以一件物品也去不掉。
转化为01背包问题求解既然01背包问题是最基本的背包问题,那么我们可以考虑把完全背包问题转化为01背包问题来解。
最简单的想法是,考虑到第i种物品最多选V/c [i]件,于是可以把第i种物品转化为V/c[i]件费用及价值均不变的物品,然后求解这个01背包问题。
这样完全没有改进基本思路的时间复杂度,但这毕竟给了我们将完全背包问题转化为01背包问题的思路:将一种物品拆成多件物品。
更高效的转化方法是:把第i种物品拆成费用为c[i]*2^k、价值为w[i]*2^k的若干件物品,其中k满足c[i]*2^k<V。
这是二进制的思想,因为不管最优策略选几件第i种物品,总可以表示成若干个2^k件物品的和。
这样把每种物品拆成O(log(V/c[i]))件物品,是一个很大的改进。
但我们有更优的O(VN)的算法。
* O(VN)的算法这个算法使用一维数组,先看伪代码: fori=1..N for v=0..Vf[v]=max{f[v],f[v-c[i]]+w[i]};你会发现,这个伪代码与P01的伪代码只有v的循环次序不同而已。
为什么这样一改就可行呢?首先想想为什么P01中要按照v=V..0的逆序来循环。
这是因为要保证第i次循环中的状态f[i][v]是由状态f[i-1][v-c[i]]递推而来。
换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入第i件物品”这件策略时,依据的是一个绝无已经选入第i件物品的子结果f[i-1][v-c[i]]。
而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第i 种物品”这种策略时,却正需要一个可能已选入第i种物品的子结果f[i][v-c[i]],所以就可以并且必须采用v= 0..V的顺序循环。
这就是这个简单的程序为何成立的道理。
这个算法也可以以另外的思路得出。
例如,基本思路中的状态转移方程可以等价地变形成这种形式:f[i][v]=max{f[i-1][v],f[i][v-c[i]]+w[i]},将这个方程用一维数组实现,便得到了上面的伪代码。
总结完全背包问题也是一个相当基础的背包问题,它有两个状态转移方程,分别在“基本思路”以及“O(VN)的算法“的小节中给出。
希望你能够对这两个状态转移方程都仔细地体会,不仅记住,也要弄明白它们是怎么得出来的,最好能够自己想一种得到这些方程的方法。
事实上,对每一道动态规划题目都思考其方程的意义以及如何得来,是加深对动态规划的理解、提高动态规划功力的好方法。
P03: 多重背包问题题目有N种物品和一个容量为V的背包。
第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。
求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
基本算法这题目和完全背包问题很类似。
基本的方程只需将完全背包问题的方程略微一改即可,因为对于第i种物品有n[i]+1种策略:取0件,取1件……取n[i]件。
令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值,则:f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k<=n[i]}。
复杂度是O(V*∑n[i])。
转化为01背包问题另一种好想好写的基本方法是转化为01背包求解:把第i种物品换成n[i]件01背包中的物品,则得到了物品数为∑n[i]的01背包问题,直接求解,复杂度仍然是O(V*∑n[i])。
但是我们期望将它转化为01背包问题之后能够像完全背包一样降低复杂度。
仍然考虑二进制的思想,我们考虑把第i种物品换成若干件物品,使得原问题中第i种物品可取的每种策略——取0..n[i]件——均能等价于取若干件代换以后的物品。
另外,取超过n[i]件的策略必不能出现。
方法是:将第i种物品分成若干件物品,其中每件物品有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数。
使这些系数分别为1,2,4,...,2^(k-1),n[i]-2^k+1,且k是满足n[i]-2^k+1>0的最大整数。
例如,如果n[i]为13,就将这种物品分成系数分别为1,2,4,6的四件物品。
分成的这几件物品的系数和为n[i],表明不可能取多于n[i]件的第i种物品。
另外这种方法也能保证对于0..n[i]间的每一个整数,均可以用若干个系数的和表示,这个证明可以分0..2^k-1和2^k..n[i]两段来分别讨论得出,并不难,希望你自己思考尝试一下。
这样就将第i种物品分成了O(log n[i])种物品,将原问题转化为了复杂度为O(V*∑log n[i])的01背包问题,是很大的改进。
O(VN)的算法多重背包问题同样有O(VN)的算法。
这个算法基于基本算法的状态转移方程,但应用单调队列的方法使每个状态的值可以以均摊O(1)的时间求解。
由于用单调队列优化的DP已超出了NOIP 的范围,故本文不再展开讲解。
我最初了解到这个方法是在楼天成的“男人八题”幻灯片上。
小结这里我们看到了将一个算法的复杂度由O(V*∑n[i])改进到O(V*∑log n[i])的过程,还知道了存在应用超出NOIP范围的知识的O(VN)算法。
希望你特别注意“拆分物品”的思想和方法,自己证明一下它的正确性,并用尽量简洁的程序来实现。
P04: 混合三种背包问题问题如果将P01、P02、P03混合起来。
也就是说,有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包)。
应该怎么求解呢?01背包与完全背包的混合考虑到在P01和P02中最后给出的伪代码只有一处不同,故如果只有两类物品:一类物品只能取一次,另一类物品可以取无限次,那么只需在对每个物品应用转移方程时,根据物品的类别选用顺序或逆序的循环即可,复杂度是O(VN)。