背包问题培训学案.docx
- 文档编号:30376522
- 上传时间:2023-08-14
- 格式:DOCX
- 页数:17
- 大小:37.12KB
背包问题培训学案.docx
《背包问题培训学案.docx》由会员分享,可在线阅读,更多相关《背包问题培训学案.docx(17页珍藏版)》请在冰豆网上搜索。
背包问题培训学案
背包问题
(2)
2010年3月11日晚
培训内容:
1、砝码称重的背包解法。
2、SubsetSums集合的背包解法。
3、数字游戏。
4、滚动数组的应用。
砝码称重的背包解法
【问题分析】11122333
把问题稍做一个改动,已知a1+a2+a3+a4+a5+a6个砝码的重量w[i],w[i]∈{1,2,3,5,10,20}其中砝码重量可以相等,求用这些砝码可称出的不同重量的个数。
这样一改就是经典的0/1背包问题的简化版了。
把a1个砝码看成0/1背包中的第1个物品,重量与价值均为a1*1。
把a2个砝码看成0/1背包中的第2个物品,重量与价值均为a2*2。
只是要注意这个题目不是求最大载重量,是统计所有的可称出的重量的个数。
programfmcz;
constw:
array[1..6]of1..20=(1,2,3,5,10,20);
maxll=1001;
var
i,j:
longint;
a,b:
array[1..10]oflongint;
f:
array[1..1001]oflongint;
begin
fori:
=1to6do
begin
read(a[i]);
b[i]:
=a[i]*w[i];
end;
readln;
fori:
=1to6do
begin
forj:
=maxlldowntob[i]do
begin
iff[j-b[i]]+b[i]>f[j]thenf[j]:
=f[j-b[i]]+b[i];{体积与价值相同}
end;
end;
writeln(f[maxll]);{maxll能达到多少就有多少种重量}
end.
砝码称重的测试数据如下:
4.1110000Total=3
4.2220000Total=6
4.3103000Total=7
4.4340500Total=36
4.5222222Total=82
4.6032745Total=185
4.7063421Total=79
4.8123456Total=204
4.8654321Total=83
4.101010101011Total=140
SubsetSums集合背包解法
SubsetSums
集合
对于从1到N的连续整集合合,能划分成两个子集合,且保证每个集合的数字和是相等的。
举个例子,如果N=3,对于{1,2,3}能划分成两个子集合,他们每个的所有数字和是相等的:
∙{3}and{1,2}
这是唯一一种分发(交换集合位置被认为是同一种划分方案,因此不会增加划分方案总数)
如果N=7,有四种方法能划分集合{1,2,3,4,5,6,7},每一种分发的子集合各数字和是相等的:
∙{1,6,7}and{2,3,4,5}{注1+6+7=2+3+4+5}
∙{2,5,7}and{1,3,4,6}
∙{3,4,7}and{1,2,5,6}
∙{1,2,4,7}and{3,5,6}
给出N,你的程序应该输出划分方案总数,如果不存在这样的划分方案,则输出0。
程序不能预存结果直接输出。
PROGRAMNAME:
subset
INPUTFORMAT
输入文件只有一行,且只有一个整数N
SAMPLEINPUT(filesubset.in)
7
OUTPUTFORMAT
输出划分方案总数,如果不存在则输出0。
SAMPLEOUTPUT(filesubset.out)
4
当1到n的总和为奇数时,一定没有一种方案,可以直接输出0,否则把总和div2当作背包的容量,用1到n个数去做0/1背包,把每一种情况加起来,状态方程:
f[j]=f[j]+f[j-i],由于n个数都使用了两次,所以情况总数也就是答案的2倍,所以输出时div2就可以了。
不知道为什么的请看下面:
如n=3时,s=3;集合有[{1,2}和{3},{3}和{1,2}]这样就重复了,所以div2。
f[j]集合的是由{j-i}和{i}组合的.f[j-i]有几种情况,那j-i和i的组合就有几种情况了,这是加法原理。
}
programsubset;
varn,i,j:
longint;
s:
int64;
st:
array[0..390]ofint64;
begin
assign(input,'subset.in');reset(input);
assign(output,'subset.out');rewrite(output);
whilenoteofdo
begin
read(n);
s:
=(n+1)*nshr1;
ifsand1=1thenwriteln(0)
else
begin
s:
=sshr1;
fori:
=1tondo
forj:
=sdowntoido
f[j]:
=f[j]+f[j-i];
writeln(f[s]shr1);
end;
end;
close(input);close(output);
end.
varf:
array[0..100000]ofint64;
i,n,m,j:
longint;
begin
assign(input,'subset.in');
reset(input);
assign(output,'subset.out');
rewrite(output);
readln(n);
close(input);
m:
=(1+n)*ndiv2;
ifmmod2=1thenbeginwriteln('0');close(output);halt;end;
m:
=mdiv2;
f[0]:
=1;
fori:
=1tondo
begin
forj:
=m-idownto0do
f[i+j]:
=f[i+j]+f[j];{f[m]=f[m]+f[m-1]f[m-1]=f[m-1]+f[m-2]}
end;
writeln(f[m]div2);
close(output);
end.
动态规划一般解决两类问题,一类是最优化问题,就是问你最大价值最小数什么的,另一类是方案总数问题。
滚动数组
滚动数组就是动态规划时反复利用已开辟的空间,丢弃大量无用数组的方法
作用是大规模动规时省内存
常用于DP之中,在DP过程中,我们在由一个状态转向另一个状态时,很可能之前存储的某些状态信息就已经无用了,例如在01背包问题中,从理解角度讲我们应开DP[i][j]的二维数组,第一维我们存处理到第几个物品,也就是阶段了,第二维存储容量,但是我们获得DP[i],只需使用DP[i-1]的信息,DP[i-k],k>1都成了无用空间,因此我们可以将数组开成一维就行,迭代更新数组中内容,滚动数组也是这个原理,目的也一样,不过这时候的问题常常是不可能缩成一维的了,比如一个DP[i][j]需要由DP[i-1][k],DP[i-2][k]决定,i 不知道怎么说? 举个例子 d[0]d[1]d[2]d[3]d[4]d[5]d[6]d[7]d[8] 112358132134 d: array[1..100]ofinteger; d[0]=1;d[1]=1; for(i=2;i<100;i++) d[i]=d[i-1]+d[i-2]; printf("%d",d[99]); 上面这个循环d[i]只依赖于前两个数据d[i-1]和d[i-2]; 为了节约空间用滚动数组的做法 d: array[1..100]ofinteger; d[0]d[1]d[2]d[0]d[1]d[2]d[0]d[1]d[2] 112358132134 d[0]=1;d[1]=1; for(i=2;i<100;i++) d[i%3]=d[(i-1)%3]+d[(i-2)%3]; printf("%d",d[99%3]); 注意上面的取余运算,我们成功地只保留了需要的最后3个解,数组好象在“滚动”一样,所以叫滚动数组 对于二维也可以用(代码可能不太正确和完善,但是可以理解例子): inti,j,d[100][100]; for(i=1;i<100;i++) for(j=0;j<100;j++) d[i][j]=d[i-1][j]+d[i][j-1]; 上面的d[i][j]只依赖于d[i-1][j],d[i][j-1]; 运用滚动数组 inti,,j,d[2][100]; for(i=1;i<100;i++) for(j=0;j<100;j++) d[i%2][j]=d[(i-1)%2][j]+d[i%2][j-1]; 光光的作业(homework) [问题描述] 光光上了高中,科目增多了。 在长假里,光光的老师们都非常严厉,都给他布置了一定量的作业。 假期里,光光一共有的时间是k小时。 在长假前,老师们一共给光光布置了n份作业,第i份作业需要的时间是ti小时。 但是由于老师们互相不商量,因此光光有可能不能完成老师的作业。 当可能不能完成老师的作业时,光光就事后去向老师说明,然后被老师批评一顿了事。 对于一件作业,只有2种情况: 完成或者不完成(快要完成也算不完成)。 如果没完成,受到批评是天经地义的。 但是,不同的作业对于光光来说,批评的力度是不同的。 第i件作业如果没完成,就要受到pi个单位的批评。 多次这样之后,光光想要在长假前就知道他至少会受到多少个单位的批评。 你能帮助他吗? [输入] 输入文件homework.in包含以下内容: 第一行只有一个数字k。 第二行只有一个数字n。 接下来n行,每行两个数字,分别是ti和pi,两个数字之间用一个空格分开。 100%的数据中,k<=100000,ti<=10000,pi<=10000; 30%的数据中,n<=20; 100%的数据中,n<=500。 [输出] 输出文件homework.out仅包含一行,是一个数字,代表了光光最少受到的批评。 [样例] homework.in 5 3 26 13 47 homework.out 6 滚动数组例题: var f: array[0..1,0..100000]oflongint; t,p: array[1..500]ofinteger; k,n,i,j,c,c2,pall: longint; begin //assign(input,'homework.in');reset(input); //assign(output,'homework.out');rewrte(output); readln(k); readln(n); pall: =0; fillchar(f,sizeof(f),0); fori: =1tondobegin readln(t[i],p[i]); pall: =pall+p[i]; forj: =t[i]tokdo iff[0,j] =p[i]; end; c: =0; fori: =1tondobegin c: =1-c; forj: =1tokdobegin f[c,j]: =f[c,j-1]; ifj-t[i]>0then iff[1-c,j-t[i]]+p[i]>f[c,j]thenf[c,j]: =f[1-c,j-t[i]]+p[i];(mod2) end; end; writeln(pall-f[c,k]); //close(input);close(output); end. 1、P34: 数字游戏 要求: 能读懂该程序;能回答该题后面提出的一个问题: 把两阶段的程序段合并成一段。 思考: 如果要将ai、ai+1、ai+2……、aj-1、aj分成p部分,怎样分? 1≤i≤n 1≤j≤n i≤k≤j-1 将ai、ai+1……、ak、ak+1、ak+2……aj 分成p-1部分分成第p部分 比如: 把1、2、3、4、5、6分成2部分, 123456 第m部分 如果ai、ai+1……、ak、ak+1、ak+2……aj不在一条直线上,而是在圆周上,怎么划分呢? m-1部分由i..j组成。 第m部分由1..i-1和j+1..n组成。 m-1部分 fori: =1tondo{计算一部分内的数和对10的模的所有可能情况} forj: =i+1tondo begin g[i,j]: =(g[i,j-1]+g[j,j])mod10; fmax1[i,j]: =g[i,j]; fmin1[i,j]: =g[i,j]; end;{for} forp: =2tom-1do{阶段: 递推计算划分2部分…m-1部分的结果值} begin fillchar(fmax,sizeof(fmax),0);{划分p部分的状态转移方程初始化} fillchar(fmin,sizeof(fmin),$FF); fori: =1tondo{状态: 枚举被划分为p部分的数字区间} forj: =itondo fork: =itoj-1do{决策: ai..ak被划分成p-1部分} begin iffmax1[i,k]*g[k+1,j]>fmax[i,j]then {计算将ai、ai+1、…aj划分成p个部分的状态转移方程} fmax[i,j]: =fmax1[i,k]*g[k+1,j]; if(fmin1[i,k]>=0)and((fmin1[i,k]*g[k+1,j] fmin[i,j]: =fmin1[i,k]*g[k+1,j]; end;{for} fmin1: =fmin;fmax1: =fmax; end;{for} max: =0;min: =maxlongint;{将a1、a2、…an划分成m个部分的最大值和最小值初始化} ifm=1then{计算n个数划分成一部分的最大值和最小值} beginmax: =g[1,n];min: =g[1,n];end{then} elsefori: =1tondo{将a1…ai-1、aj+1…an设为第m部分,计算最大值和最小值} forj: =itondo if(i<>1)or(j<>n)then begin if(g[1,i-1]+g[j+1,n])mod10*fmax1[i,j]>maxthen max: =(g[1,i-1]+g[j+1,n])mod10*fmax1[i,j]; if(fmin1[i,j]>=0)and((g[1,i-1]+g[j+1,n])mod10*fmin1[i,j] min: =(g[1,i-1]+g[j+1,n])mod10*fmin1[i,j]; end;{then} writeln(min);writeln(max);{输出最小值和最大值} 本题的计算过程分两个阶段 第一个阶段: 将圆周上的n个数排成一个序列,计算ai、ai+1、…aj划分成m-1个部分的最大值fmax1[i,j]和最小值fmin1[i,j]; 第二个阶段: 将序列首尾相接。 枚举第m部分的所有可能情况,在fmax1和fmin1的基础上,计算圆周上的n个数划分成m个部分的最大值max和最小值min。 由于是一个圈,所以要从1-n中的每个点打断进行DP,最后统计最大最小值 思考: 能否将两个阶段合并,用一个状态转移方程来解决呢? 请修改程序。 6mod10=(-4)mod10=6 将N个数拉成2N个数的链,秒杀 vari,j,k,m,n,l,max,min,value: longint; a: array[1..50]oflongint; sum: array[0..100]oflongint; f,g: array[1..50,1..10]oflongint; functionmin1(i,j: longint): longint; begin ifi exit(j); end; functionget(i,j: longint): longint; 2 begin get: =sum[j]-sum[i-1]; ifget<0theninc(get,100000000); get: =getmod10; end; 4 -1 begin max: =-maxlongint; min: =maxlongint; readln(n,m); 3 fori: =1tondo begin read(a[i]); inc(sum[i],sum[i-1]+a[i]);(sum[1]=2sum[2]=1sum[3]=4sum[4]=8) end; fori: =1tondo inc(sum[i+n],sum[i+n-1]+a[i]); fori: =1tondo begin value: =get(i,i); f[1,1]: =value; g[1,1]: =value; forj: =2tondo begin value: =get(i,i+j-1); f[j,1]: =value; g[j,1]: =value; fork: =2tomin1(j,m)do begin f[j,k]: =-maxlongint; g[j,k]: =maxlongint; forl: =1toj-1do begin value: =get(l+i,j+i-1); ifvalue*f[l,k-1]>f[j,k]thenf[j,k]: =value*f[l,k-1]; ifvalue*g[l,k-1] =value*f[l,k-1] end; end; end; ifmax =f[n,m]; ifmin>g[n,m]thenmin: =g[n,m]; end; writeln(min); writeln(max); end. vara,b: array[0..100]oflongint; f1,f2: array[0..10,0..52]oflongint; num: array[0..51,0..51]oflongint; n,m,i,t,max1,min1,j,k: longint; functionmax(x,y: longint): longint; begin ifx>ythenmax: =xelsemax: =y; end; functionmin(x,y: longint): longint; begin ifx>ythenmin: =yelsemin: =x; end; begin readln(n,m); fori: =1tondoreadln(a[i]); a[0]: =a[n]; max1: =-maxlongint; min1: =maxlongint; fort: =1tondo begin fillchar(num,sizeof(num),0); fillchar(b,sizeof(b),0); fillchar(f1,sizeof(f1),0); fillchar(f2,sizeof(f2),0); fori: =ttot+n-1dob[i-t+1]: =a[imodn]; fori: =1tondo forj: =itondonum[i,j]: =(num[i,j-1]+((b[j]+10000000)mod10))mod10; fori: =1tondo begin f1[1,i]: =num[1,i]; f2[1,i]: =num[1,i]; end;
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 背包 问题 培训
![提示](https://static.bdocx.com/images/bang_tan.gif)