用动态规算法求出的0-1背包问题,写出完整的可以运行的程序,并且给出算法复杂性的分析与结果,谢谢

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用动态规算法求出的0-1背包问题,写出完整的可以运行的程序,并且给出算法复杂性的分析与结果,谢谢相关的知识,希望对你有一定的参考价值。

0-1背包问题:给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为c。问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大?
在选择装入背包的物品时,对每种物品i只有两种选择,即装入背包或不装入背包。不能将物品i装入背包多次,也不能只装入部分的物品i。因此,该问题成为0-1背包问题。
用C++或C#来编写,用动态规划算法来实现

1.0-1背包: 每个背包只能使用一次或有限次(可转化为一次):
A.求最多可放入的重量。
NOIP2001 装箱问题
有一个箱子容量为v(正整数,o≤v≤20000),同时有n个物品(o≤n≤30),每个物品有一个体积 (正整数)。要求从 n 个物品中,任取若千个装入箱内,使箱子的剩余空间为最小。
l 搜索方法
procedure search(k,v:integer);
var i,j:integer;
begin
if v<best then best:=v;
if v-(s[n]-s[k-1])>=best then exit;
if k<=n then begin
if v>w[k] then search(k+1,v-w[k]);
search(k+1,v);
end;
end;

l DP
F[I,j]为前i个物品中选择若干个放入使其体积正好为j的标志,为布尔型。
实现:将最优化问题转化为判定性问题
f [I, j] = f [ i-1, j-w[i] ] (w[I]<=j<=v) 边界:f[0,0]:=true.
For I:=1 to n do
For j:=w[I] to v do F[I,j]:=f[I-1,j-w[I]];
优化:当前状态只与前一阶段状态有关,可降至一维。
F[0]:=true;
For I:=1 to n do begin
F1:=f;
For j:=w[I] to v do
If f[j-w[I]] then f1[j]:=true;
F:=f1;
End;

B.求可以放入的最大价值。
F[I,j] 为容量为I时取前j个背包所能获得的最大价值。
F [i,j] = max

C.求恰好装满的情况数。
DP:
Procedure update;
var j,k:integer;
begin
c:=a;
for j:=0 to n do
if a[j]>0 then
if j+now<=n then inc(c[j+now],a[j]);
a:=c;
end;

2.可重复背包
A求最多可放入的重量。
F[I,j]为前i个物品中选择若干个放入使其体积正好为j的标志,为布尔型。
状态转移方程为
f[I,j] = f [ I-1, j – w[I]*k ] (k=1.. j div w[I])

B.求可以放入的最大价值。
USACO 1.2 Score Inflation
进行一次竞赛,总时间T固定,有若干种可选择的题目,每种题目可选入的数量不限,每种题目有一个ti(解答此题所需的时间)和一个si(解答此题所得的分数),现要选择若干题目,使解这些题的总时间在T以内的前提下,所得的总分最大,求最大的得分。
*易想到:
f[i,j] = max (0<=k<= i div w[j])
其中f[i,j]表示容量为i时取前j种背包所能达到的最大值。
*实现:
Begin
FillChar(f,SizeOf(f),0);
For i:=1 To M Do
For j:=1 To N Do
If i-problem[j].time>=0 Then
Begin
t:=problem[j].point+f[i-problem[j].time];
If t>f[i] Then f[i]:=t;
End;
Writeln(f[M]);
End.

C.求恰好装满的情况数。
Ahoi2001 Problem2
求自然数n本质不同的质数和的表达式的数目。
思路一,生成每个质数的系数的排列,在一一测试,这是通法。
procedure try(dep:integer);
var i,j:integer;
begin
cal;
if now>n then exit;
if dep=l+1 then begin
cal;
if now=n then inc(tot);
exit;
end;
for i:=0 to n div pr[dep] do begin
xs[dep]:=i;
try(dep+1);
xs[dep]:=0;
end;
end;

思路二,递归搜索效率较高
procedure try(dep,rest:integer);
var i,j,x:integer;
begin
if (rest<=0) or (dep=l+1) then begin
if rest=0 then inc(tot);
exit;
end;
for i:=0 to rest div pr[dep] do
try(dep+1,rest-pr[dep]*i);
end;

思路三:可使用动态规划求解
USACO1.2 money system
V个物品,背包容量为n,求放法总数。
转移方程:

Procedure update;
var j,k:integer;
begin
c:=a;
for j:=0 to n do
if a[j]>0 then
for k:=1 to n div now do
if j+now*k<=n then inc(c[j+now*k],a[j]);
a:=c;
end;

begin
read(now);
i:=0;
while i<=n do begin
a[i]:=1; inc(i,now); end;
for i:=2 to v do
begin
read(now);
update;
end;
writeln(a[n]);
参考技术A 01背包 2个状态
一个背包只有取或不取
前I个背包去装J的空间
考虑2种情况 F[I,J]:=MAX ( F[I-1,J],F[I-1,J-V[I]]+W[I])
F[I-1,J]表示第I个不取 则F[I,J]与用前I-1个装J相同
F[I-1,J-V[I]]+W[I]表示第I个取 即用前I-1个装J-V[I] (表示前I-1 装J-V[I])
然后再加上第I个的价值
这两个取最大的
fillchar(a,sizeof(a),0);
FOR I:=1 TO N DO
FOR J:=1 to m do
if (j-v[i]>=0)and( [I-1,J-V[I]]+W[I]> F[I-1,J]) then f[i,j]:=[I-1,J-V[I]]+W[I]
else f[i,j]:=f[i-1,j];
writeln(f[n,m]);
初始化全赋值为0 数组从0开始
你可以去看看背包9讲 百度文库有
去RQ 或TYVJ 做些题就行了 必须做题

以上是关于用动态规算法求出的0-1背包问题,写出完整的可以运行的程序,并且给出算法复杂性的分析与结果,谢谢的主要内容,如果未能解决你的问题,请参考以下文章

图解算法-怎么用动态规划解决0-1背包问题

背包问题(贪心算法)

告别动态规划,连刷40道动规算法题,我总结了动规的套路

动规基础——01背包问题(背包问题Ⅱ)

考虑下述背包问题的实例。有5件物品,背包容量为100。

动态规划一:01背包问题