背包再讲.docx
- 文档编号:29823606
- 上传时间:2023-07-27
- 格式:DOCX
- 页数:12
- 大小:24.58KB
背包再讲.docx
《背包再讲.docx》由会员分享,可在线阅读,更多相关《背包再讲.docx(12页珍藏版)》请在冰豆网上搜索。
背包再讲
背包再讲
背包是我们学习动归中的基础题目,相信每一位同学对于背包都已经有了自己的认识,背包九将中我们已经认识了
1.01背包
fori=1..N
forv=0..V
f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}
f[v]=max{f[v],f[v-cost]+weight}
2.完全背包
f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<=v}
fori=1..N
forv=0..V
f[v]=max{f[v],f[v-cost]+weight}
3.多重背包
f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k<=n[i]}
4.混合背包
fori=1..N
if第i件物品是01背包
forv=V..0
f[v]=max{f[v],f[v-c[i]]+w[i]};
elseif第i件物品是完全背包
forv=0..V
f[v]=max{f[v],f[v-c[i]]+w[i]};
5.二维费用背包
fori=1..N
if第i件物品是01背包
ZeroOnePack(c[i],w[i])
elseif第i件物品是完全背包
CompletePack(c[i],w[i])
elseif第i件物品是多重背包
MultiplePack(c[i],w[i],n[i])
6.有依赖的背包
金明的预算方案
以上6中就是背包问题中的基础问题,作为动归中的经典,背包有着广泛的应用,对于很多题目,我们可以采用“平移”的办法,或者是其他的方法,讲一道复杂的动态规划问题转变为背包问题,或者说装箱问题。
解决背包的关键思想:
“取或不取”。
理解到了这个思想,对于背包你才掌握了它的精髓,你也就解决了所有的背包类问题。
装箱问题是背包中简单转化,顾名思义,装箱问题的来源是这样一道题
现在码头上有一堆集装箱,每一个集装箱都占有一定的空间a[i],你现在要做的事情是把这些集装箱装到一艘容量为m的货轮上要求是尽可能的装满,也就是剩余空间尽可能的少
这道题该怎么解?
给你三个选项
贪心?
(你真sb)
深搜?
(你真蛋疼)
动态规划?
(恭喜你,赢得了讲解权)
当然,我要讲得肯定是动态规划,大家想想,这道题和背包有什么联系?
背包对于这件物品所作的处理是取或不取
这道题也可以借鉴这样的思路,我们设置一个布尔数组f[i][j],f[i][j]表示前i个物品装了j的空间这个状态是受否存在,现在我们来想一想动态规划过程是怎么样的
1.如果f[i-1][j-a[i]]存在,表示前i-1个物品可以使用j-a[i]的空间
那么在装进了这个物品之后f[i][j]当然也存在
2.如果f[i-1][j-a[i]]不存在那么f[i][j]就不可能存在。
最后我们从f[n][m]开始找起,找到的第一个存在的f[n][i]就是我们的答案了
所以这道题的动态规划方程如下
F[i][j]=1(f[i-1][j-a[i]=1]),0(f[i-1][j-a[i]]=0);
大家觉得这样有什么问题吗?
大家在看完这道题之后,是不是有一种大炮打蚊子的感觉,说白了就是一个简单的递推,与第i件物品的取或不取并没有什么联系,但是与01背包一样,这道题是一切装箱问题的来源,从中延伸出来的问题很多。
下面就进入我们要讲的问题,其他问题转化为背包问题求解,或者说是转化为装箱问题求解。
先看这一题。
搭建双塔问题来源复赛书第七套第一题
给出N个木块,告诉你每个木块的高度,你要用这些木块搭建出两座高度相同的她,一座塔的高度为搭建它的木块的高度和,并且一座塔至少要用一个木块。
木块只能用一次,也可以不用。
问在两座她的高度相同的限制下,能够搭建的塔的最大高度是多少?
这道题很多同学都已经做过了,对于这道题来说,并没有其他的解法,只有用背包问题才能求解。
刚才我已经讲过了,解决背包问题的关键在于四个字:
“取或不取”,对于这道题来说,搞清楚这个问题,是将其转化的关键
取or不取?
要判断这个问题,关键是判断取或者不取对于这个状态有什么影响。
取:
1.放在第一座塔上
2.放在第二座的塔上
是不是只有这两种可能?
没错答案是肯定的,那么对于状态有什么影响?
加入第一座塔比第二座塔高h,如果我们将这个木块放在第一座塔上,那么是不是第一座塔就比第二座塔高h+a[i].反之,如果把木块放在第二座塔上,那么第一座塔就比第二座塔高h-a[i]。
如果不取,那么第一座塔是不是比第二座塔依然高h。
最后我们要的到的答案是什么?
没错,就是在第n块木块处理完成后,h=0;
也就是f[n][0];
经过上面的分析我们很容易写出下面的动态规划方程:
F[i][j]表示已经处理完前i个木块,第一座塔比第二座塔高h时,第一座塔的高度是多少。
转移情况分为三种:
1.不用木块i.f[i][j]=f[i-1][j].
2.将木块放到第一座塔上f[i][j]=f[i-1][j-length[i]]+lengh[i];
3.将木块放到第三座塔上f[i][j]=f[i-1][j+length[i]];
最后答案为f[n][0];
到现在,这道题就算解决了,我们再来总结一下,这道题的思考过程,这道题我们发现,这道题不同于我们以前见到过的背包,我们没有使用价值这个状态,只是使用了高度也就是背包的占用空间这样一个状态,是不是类似于装箱问题,高度就是箱子的体积,只是这个问题更加的复杂,转移的过程更加多种。
在思维的过程中,突破口就是我反复提到的四个字:
“取或不取”。
对于一个木块,取或不取就是我们对于它所作的处理,这一步处理好了,这道题就迎刃而解。
下面介绍的一种重要的转化方法:
“平移”
平移是背包类问题的关键转化步骤,平移的意思简单的意思就是在背包问题中,空间这一个量的取值范围是0……n。
但是在很多的问题中类似空间的量很多情况下都是有负数的,最后结果也不是m,而是0,这时,我们就学要对于这个量进行一个处理:
“同加同减”将符号统一,这样就可以使用背包了。
下面是一道例题,也是很多同学做过但是没做出来的题
多米诺骨牌来源(紫色封面的那本,8.5)
【问题描述】
多米诺骨牌有上下2个方块组成,每个方块中有1~6个点。
现有排成行的n个多米诺骨牌如图8-1所示。
●●
●●
●●
●
●
●
●
●●
●
●●
●
●
●
●
●
上方块中点数之和记为
,下方块中点数之和记为
,它们的差为
。
例如在图8-1中,
=6+1+1+1=9,
=1+5+3+2=11,
=2。
每个多米诺骨牌可以旋转180°,使得上下两个方块互换位置。
编程用最少的旋转次数使多米诺骨牌上下2行点数之差达到最小。
对于图8-1中的例子,只要将最后一个多米诺骨牌旋转180°,可使上下2行点数之差为0。
【输入】
输入文件的第一行是一个正整数n(1≤n≤1000),表示多米诺骨牌数。
接下来的n行表示n个多米诺骨牌的点数。
每行有两个用空格隔开的正整数,表示多米诺骨牌上下方块中的点数a和b,且1≤a,b≤6。
【输出】
输出文件仅一行,包含一个整数。
表示求得的最小旋转次数。
【样例】
dom.indom.out
41
61
15
13
12
这道题乍一看很不好解,很多同学肯定会马上想到使用贪心或者是深搜,其实我再一开始的时候这道题我也以为是贪心,我的思想是将所有的点数加起来,二分,答案就是最后答案,然后将差值最接近答案的组进行旋转,但是这样很容易就举出了反例。
深搜是我想到的第二个算法,但是一看数据范围1≤n≤1000,立马放弃。
然后我就想到了动态规划,
我最初的设想是这样的f[i][j]表示前i个骨牌,翻转了j次之后上下之间的最下差值,那么前面的最小差值+这一块的最小差值就是现在的最小差值。
这样对吗?
?
?
仔细一想,就能发现,这肯定是错误的,很简单,前面最小+现在最小可能大于前面最大-现在最大。
举一组反例
有三块骨牌点数分别为2.14.32.4;
前两个的最下差值是0,但是加上第三个就变成了2,其实答案是0;
这个想法被否决了之后,我们就来看看这道题的与背包的关系。
我反复说过,解决背包问题的关键在于:
“取或不取”。
对于这道题来说每一块骨牌的差值是一定的,我们要做的就是翻或者不翻,也就是取或不取。
但是我们发现这里的差值是有负数的,对于负数我们不能使用动归,所以这里就要使用我刚刚讲过的一个方法:
“平移”
假设一块骨牌的差值为–Si----Si,我们把每一块骨牌的差值加上Si,那么这块骨牌的差值就变成了0-----2*Si,最后答案的最小差值也就从0变成了ΣSi,也就是我们的空间m。
现在这道题就变成了这样,有n块骨牌,每块骨牌的价值是2*Si
要求你用在最接近ΣSi的综合下使用的骨牌最少。
现在这道题是不是简单多了,仔细一看,这是不是就是我们的装箱问题呢?
?
F[i,j]表示到第i个骨牌取得j的差值所需要的最小翻转次数。
很明显
F[i,j]=min{f[i-1,j]+tp1,f[i-1,j-w[i]]+tp2}
对于tp1,tp2的值只能使0,1表示是否需要翻转
当a[i]>b[i]时:
f[i-1,j]表示第i个取0,但是第i个如果不翻转将会大于0,所以这时tp1=1。
f[i-1,j-w[i]]表示第i各取w[i],因为第i个
如果不翻转它的值本来就大于0,所以tp2=0;
当a[i]
同样f[i-1,j]表示的是第i各取0,如果第i各不翻转那么它本来就是0,所以不翻转,tp1=0。
F[i-1,j-w[i]]表示第i各取w[i],如果不翻转值为0,那么需要翻转一次,所以tp2=1;
还有一种情况并没有处理,那就是a[i]=b[i]时,无论是f[i-1,j],f[i-1,j-w[i]]它们都只能取0,因为不管翻不翻转值都是0,所以tp1=tp2=0.
还有就是开始时候的边界情况
如果a[1]>b[1]f[1,0]=1,f[1,w[1]]=0
如果a[1]
如果a[1]=b[1]f[1,0]=0,f[1,w[1]]=0
可以根据上面的分析得到。
如果不平移那么上下之差最小就是最接近0的,不过现在我们把所有都向右平移了2倍,所以上下之差最小应该是最接近MAX/2
程序如下:
#include
#include
inti,j,k,f[12001]={0},a[1001],n,maxz=0,maxf=0,now=0;
intmain()
{FILE*fin=fopen("dom.in","r");
FILE*fout=fopen("dom.out","w");
fscanf(fin,"%d",&n);
for(i=0;i { fscanf(fin,"%d%d",&j,&k); a[i]=j-k; if(a[i]<0)maxf-=a[i]; elsemaxz+=a[i]; now+=a[i]; } f[now+maxf]=1; for(i=0;i if(a[i]>0) { for(j=2*a[i];j<=maxz+maxf;j++) if(f[j]>0&&(f[j-2*a[i]]==0||f[j-2*a[i]]>f[j]+1)) f[j-2*a[i]]=f[j]+1; } elseif(a[i]<0) { for(j=maxz+maxf+2*a[i];j>=0;j--) if(f[j]>0&&(f[j-2*a[i]]==0||f[j-2*a[i]]>f[j]+1)) f[j-2*a[i]]=f[j]+1; } i=maxf;j=maxf; while(f[i]==0&&f[j]==0) { i++;j--; } if(f[i]==0)fprintf(fout,"%d\n",f[j]-1); elseif(f[j]==0||f[i]<=f[j])fprintf(fout,"%d\n",f[i]-1); fclose(fin); fclose(fout); return0; } 现在我们再来回忆一下这道题,我们在否定了贪心,深搜,一般性动态规划之后,我们最终发现了这道题的奥秘所在,转化为背包问题求解,我多次强调的“取或不取”又发挥了巨大的作用,在过程中我们使用了“平移”的方法优化了问题,最终的到了完美答案。 现在我们来总结一下可以转化为背包问题求解的题的特点,首先,拥有价值或者空间属性,处理的一个点而非一段区间或者是一棵树等数据结构,对于一个点来说,可以简化为两种处理办法,“取或不取” 符合这些条件的题目就可以转化为背包问题求解。 最后布置一道作业题,希望同学们认真思考,利用背包和平移的知识,争取将它解答出来,有不懂得地方可以来问我。 8、分组 源程序名teams.? ? ? (pas,c,cpp) 可执行文件名teams.exe 输入文件名teams.in 输出文件名teams.out 【问题描述】 你的任务是把一些人分成两组,使得: ·每个人都被分到其中一组; ·每个组都至少有一个人; ·一组中的每个人都认识其他同组成员; ·两组的成员人数近两接近。 这个问题可能有多个解决方案,你只要输出任意一个即可,或者输出这样的分组法不存在。 【输入】 为了简单起见,所有的人都用一个整数标记,每个人号码不同,从1到N。 输入文件的第一行包括一个整数N(2≤N≤100),N就是需要分组的总人数;接下来的N行对应了这N个人,按每个人号码的升序排列,每一行给出了一串号码Aij(1≤Aij≤N,Aij≠i),代表了第i个人所认识的人的号码,号码之间用空格隔开,并以一个“0”结束。 【输出】 如果分组方法不存在,就输出信息“Nosolution”(输出时无需加引号)至输出文件;否则用两行输出分组方案;第一行先输出第一组的人数,然后给出第一组成员的号码,每个号码前有一个空格,同理给出第二组的信息。 每组的成员号码顺序和组别顺序并不重要。 【样例】 teams.inteams.out 53135 2350224 14530 1250 1230 43210 简单分析 首先,确定这样的一组集合(Ai,Bi),集合Ai中的人必须和集合Bi的人分在不同组。 这些集合可通过人与人之间认识与不认识的关系得到。 得到这些集合对后,问题就转化为一个背包问题了——即如何分配这些二元组,使得两边人数差尽量小。 这个背包问题可以通过“平移”的方法转化为普通的背包问题 最后再最后一次重申,非常非常非常非常非常非常重要的四个字: 取或不取
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 背包 再讲
![提示](https://static.bdocx.com/images/bang_tan.gif)