背包问题Word文档下载推荐.docx

上传人:b****6 文档编号:21524177 上传时间:2023-01-31 格式:DOCX 页数:10 大小:19.92KB
下载 相关 举报
背包问题Word文档下载推荐.docx_第1页
第1页 / 共10页
背包问题Word文档下载推荐.docx_第2页
第2页 / 共10页
背包问题Word文档下载推荐.docx_第3页
第3页 / 共10页
背包问题Word文档下载推荐.docx_第4页
第4页 / 共10页
背包问题Word文档下载推荐.docx_第5页
第5页 / 共10页
点击查看更多>>
下载资源
资源描述

背包问题Word文档下载推荐.docx

《背包问题Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《背包问题Word文档下载推荐.docx(10页珍藏版)》请在冰豆网上搜索。

背包问题Word文档下载推荐.docx

这符合动态规划中最优子问题的性质。

考虑用动态规划的方法来解决,这里的:

阶段是:

在前n件物品中,选取若干件物品放入背包中;

状态是:

在前n件物品中,选取若干件物品放入所剩空间为w的背包中的所能获得的最大价值;

决策是:

第n件物品放或者不放;

由此可以写出动态转移方程:

我们用f[i,j]表示在前i件物品中选择若干件放在所剩空间为j的背包里所能获得的最大价值

f[i,j]=max{f[i-1,j-wi]+pi(j>

=wi),f[i-1,j]}

这样,我们可以自底向上地得出在前m件物品中取出若干件放进背包能获得的最大价值,也就是f[m,w]

算法设计如下:

proceduremake;

fori:

=0towdo

f[0,i]:

=1tomdo

forj:

=0towdobegin

f[i,j]:

=f[i-1,j];

if(j>

=w[i])and(f[i-1,j-w[i]]+v[i]>

f[i,j])then

=f[i-1,j-w[i]]+v[i];

end;

writeln(f[m,wt]);

由于是用了一个二重循环,这个算法的时间复杂度是o(n*w)。

而用搜索的时候,当出现最坏的情况,也就是所有的结点都没有重叠,那么它的时间复杂度是o(2^n)。

看上去前者要快很多。

但是,可以发现在搜索中计算过的结点在动态规划中也全都要计算,而且这里算得更多(有一些在最后没有派上用场的结点我们也必须计算),在这一点上好像是矛盾的。

事实上,由于我们定下的前提是:

所有的结点都没有重叠。

也就是说,任意n件物品的重量相加都不能相等,而所有物品的重量又都是整数,那末这个时候w的最小值是:

1+2+2^2+2^3+……+2^n-1=2^n-1

此时n*w>

2^n,动态规划比搜索还要慢~~|||||||所以,其实背包的总容量w和重叠的结点的个数是有关的。

考虑能不能不计算那些多余的结点……

那么换一种状态的表示方式:

在前n件物品中,选取若干件物品放入所占空间为w的背包中的所能获得的最大价值;

阶段和决策:

同上;

状态转移方程是:

f[i,j]=max{f[i-1,j-wi]+pi(j+wi<

=背包总容量),f[i-1,j]}

这样,我们可以得出在前m件物品中取出若干件放进背包在所占空间不同的状态下能获得的最大价值,在其中搜索出最大的一个就是题目要求的解。

f[0,wt]:

=1tondo

=0tow(背包总容量)do

iff[i-1,j]未被赋过值then(这些结点与计算无关,忽略)

continue

else

=max{f[i-1,j+wi]+pi,f[i-1,j]};

最大价值:

=max{f[n,j]}(求最大值)

j:

=1tow

由于事实上在计算的过程中每一个阶段的状态都只和上一个阶段有关,所以只需要来一个两层的数组循环使用就可以了,这是动态规划中较常使用的降低空间复杂度的方法。

本题能够用动态规划的一个重要条件就是:

所有的重量值均为整数因为

1)这样我们才可以用数组的形式来储存状态;

2)这样出现子问题重叠的概率才比较大。

(如果重量是实型的话,几个重量相加起来相等的概率会大大降低)

所以,当重量不是整数的时候本题不适合用动态规划。

[解的输出]:

在计算最大价值的时候我们得到了一张表格(f[i,j]),我们可以利用这张表格输出解。

可以知道,如果f[i-1,j+wi]+v[i]=f[i,j](第二个算法),则选择物品i放入背包。

算法设计1:

进行反复的递归搜索,依次输出物品序号;

procedureout(i,j:

integer);

(初始时i=n,j=获得最大价值的物品所占的空间)

ifi=0thenexit;

iff[i,j]=f[i-1,j+w[i]]+v[i]thenbegin

输出解

out(i-1,j+w[i]);

end

else

out(i-1,j);

算法设计2:

同样的思路我们可以用循环来完成;

procedureout2;

var

i,ws:

ws:

=获得最大价值的物品所占的空间;

fori:

=ndownto1dobegin

if(ws>

=w[i])and(f[i,ws]=f[i-1,ws-w[i]]+v[i])thenbegin

输出解;

=ws-w[i];

writeln;

用这两种算法的前提是我们必须存住f[i,j]这一整个二维数组,但是如果用循环数组的话怎样输出解呢?

显然,我们只需要存住一个布尔型的二维数组,记录每件物品在不同的状态下放或者不放就可以了。

这样一来数组所占的空间就会大大降低。

[解题收获]:

1)在动态程序设计中,状态的表示是相当重要的,选择正确的状态表示方法会直接影响程序的效率。

2)针对题目的不同特点应该选择不同的解题策略,往往能够达到事半功倍的效果。

像本题就应该把握住"

所有的重量值均为整数"

这个特点。

--------------------------------------------------------------

背包问题全攻略

部分背包问题可有贪心法求解:

计算PiWi

数据结构:

w[i]第i个背包的重量;

p[i]第i个背包的价值;

(1)每个背包只能使用一次或有限次(可转化为一次):

A.求最多可放入的重量。

NOIP2001装箱问题

有一个箱子容量为v(正整数,o≤v≤20000),同时有n个物品(o≤n≤30),

每个物品有一个体积(正整数)。

要求从n个物品中,任取若千个装入箱内,使箱子的剩余空间为最小。

l搜索方法

proceduresearch(k,vinteger);

{搜索第k个物品,剩余空间为v}

vari,jinteger;

begin

ifvbestthenbest=v;

ifv-(s[n]-s[k-1])=bestthenexit;

{s[n]为前n个物品的重量和}

ifk=nthenbegin

ifvw[k]thensearch(k+1,v-w[k]);

search(k+1,v);

lDP

F[I,j]为前i个物品中选择若干个放入使其体积正好为j的标志,为布尔型。

实现将最优化问题转化为判定性问题

F[I,j]=f[i-1,j-w[i]](w[I]=j=v)边界:

f[0,0]=true.

ForI=1tondo

Forj=w[I]tovdoF[I,j]=f[I-1,j-w[I]];

优化:

当前状态只与前一阶段状态有关,可降至一维。

F[0]=true;

ForI=1tondobegin

F1=f;

Forj=w[I]tovdo

Iff[j-w[I]]thenf1[j]=true;

F=f1;

End;

B.求可以放入的最大价值。

C.求恰好装满的情况数。

(2)每个背包可使用任意次:

状态转移方程为

f[I,j]=max{f[i-w[j]

USACO1.2ScoreInflation

进行一次竞赛,总时间T固定,有若干种可选择的题目,每种题目可选入的

数量不限,每种题目有一个ti(解答此题所需的时间)和一个si(解答此题所得

的分数),现要选择若干题目,使解这些题的总时间在T以内的前提下,所得的

总分最大,求最大的得分。

易想到:

f[i,j]=max{f[i-kw[j],j-1]+kv[j]}(0=k=idivw[j])

其中f[i,j]表示容量为i时取前j种背包所能达到的最大值。

Begin

FillChar(problem,SizeOf(problem),0);

Assign(Input,'

inflate.in'

);

Reset(Input);

Readln(M,N);

Fori=1ToNDo

Withproblem[i]Do

Readln(point,time);

Close(Input);

FillChar(f,SizeOf(f),0);

Fori=1ToMDo

Forj=1ToNDo

Ifi-problem[j].time=0Then

t=problem[j].point+f[i-problem[j].time];

Iftf[i]Thenf[i]=t;

Assign(Output,'

inflate.out'

Rewrite(Output);

Writeln(f[M]);

Close(Output);

End.

Ahoi2001Problem2

求自然数n本质不同的质数和的表达式的数目。

思路一,生成每个质数的系数的排列,在一一测试,这是通法。

proceduretry(depinteger);

cal;

{此过程计算当前系数的计算结果,now为结果}

ifnownthenexit;

{剪枝}

ifdep=l+1thenbegin{生成所有系数}

ifnow=ntheninc(tot);

exit;

fori=0tondivpr[dep]dobegin

xs[dep]=i;

try(dep+1);

xs[dep]=0;

思路二,递归搜索效率较高

proceduretry(dep,restinteger);

vari,j,xinteger;

if(rest=0)or(dep=l+1)thenbegin

ifrest=0theninc(tot);

fori=0torestdivpr[dep]do

try(dep+1,rest-pr[dep]i);

思路三:

可使用动态规划求解

USACO1.2moneysystem

V个物品,背包容量为n,求放法总数。

转移方程:

Procedureupdate;

varj,kinteger;

c=a;

forj=0tondo

ifa[j]0then

fork=1tondivnowdo

ifj+nowk=ntheninc(c[j+nowk],a[j]);

a=c;

{main}

begin

read(now);

{读入第一个物品的重量}

i=0;

{a[i]为背包容量为i时的放法总数}

whilei=ndobegin

a[i]=1;

inc(i,now);

{定义第一个物品重的整数倍的重量a值为1,作为初值}

fori=2tovdo

update;

{动态更新}

writeln(a[n]);

End.

计算Pi/Wi

w[i]:

第i个背包的重量;

p[i]:

第i个背包的价值;

(1)每个背包只能使用一次或有限次(可转化为一次):

有一个箱子容量为v(正整数,o≤v≤20000),同时有n个物品(o≤n≤30),

每个物品有一个体积(正整数)。

l搜索方法

proceduresearch(k,v:

{搜索第k个物品,剩余空间为v}

vari,j:

ifv<

bestthenbest:

=v;

ifv-(s[n]-s[k-1])>

=bestthenexit;

{s[n]为前n个物品的重量和}

ifk<

=nthenbegin

ifv>

w[k]thensearch(k+1,v-w[k]);

lDP

实现:

将最优化问题转化为判定性问题

F[I,j]=f[i-1,j-w[i]](w[I]<

=j<

=v)边界:

f[0,0]:

=true.

ForI:

Forj:

=w[I]tovdoF[I,j]:

=f[I-1,j-w[I]];

F[0]:

=true;

=1tondobegin

F1:

=f;

=w[I]tovdo

Iff[j-w[I]]thenf1[j]:

F:

=f1;

(2)每个背包可使用任意次:

状态转移方程为

f[I,j]=max{f[i-w[j]

USACO1.2ScoreInflation

进行一次竞赛,总时间T固定,有若干种可选择的题目,每种题目可选入的

数量不限,每种题目有一个ti(解答此题所需的时间)和一个si(解答此题所得

的分数),现要选择若干题目,使解这些题的总时间在T以内的前提下,所得的

总分最大,求最大的得分。

*易想到:

f[i,j]=max{f[i-k*w[j],j-1]+k*v[j]}(0<

=k<

=idivw[j])

*优化:

Begin

Fori:

=1ToNDo

Withproblem[i]Do

=1ToMDo

Ifi-problem[j].time>

=0Then

t:

=problem[j].point+f[i-problem[j].time];

Ift>

f[i]Thenf[i]:

=t;

Ahoi2001Problem2

proceduretry(dep:

{此过程计算当前系数的计算结果,now为结果}

ifnow>

nthenexit;

{剪枝}

ifdep=l+1thenbegin{生成所有系数}

=0tondivpr[dep]dobegin

xs[dep]:

=i;

思路二,递归搜索效率较高

proceduretry(dep,rest:

vari,j,x:

if(rest<

=0)or(dep=l+1)thenbegin

=0torestdivpr[dep]do

try(dep+1,rest-pr[dep]*i);

可使用动态规划求解

USACO1.2moneysystem

varj,k:

c:

=a;

=0tondo

ifa[j]>

0then

fork:

=1tondivnowdo

ifj+now*k<

=ntheninc(c[j+now*k],a[j]);

a:

=c;

{main}

{读入第一个物品的重量}

i:

{a[i]为背包容量为i时的放法总数}

whilei<

=ndobegin

a[i]:

=1;

{定义第一个物品重的整数倍的重量a值为1,作为初值}

=2tovdo

{动态更新}

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 法律文书 > 起诉状

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1