当前位置:文档之家› 回溯法和分支限界法解决背包题

回溯法和分支限界法解决背包题

0-1背包问题
计科1班朱润华 32
方法1:回溯法
一、回溯法描述:
用回溯法解问题时,应明确定义问题的解空间。

问题的解空间至少包含问题的一个(最优)解。

对于0-1背包问题,解空间由长度为n的0-1向量组成。

该解空间包含对变量的所有0-1赋值。

例如n=3时,解空间为:{(0,0,0),(0,1,0),(0,0,1),(1,0,0),(0,1,1),(1,0,1),(1,1,0),(1,1,1)}然后可将解空间组织成树或图的形式,0-1背包则可用完全二叉树表示其解空间给定n种物品和一背包。

物品i的重量是wi,其价值为vi,背包的容量为C。

问:应如何选择装入背包的物品,使得装入背包中物品的总价值最大
形式化描述:给定c >0, wi >0, vi >0 , 1≤i≤n.要求找一n元向量(x1,x2,…,xn,), xi∈{0,1}, ∑ wi xi≤c,且∑ vi xi达最大.即一个特殊的整数规划问题。

二、回溯法步骤思想描述:
0-1背包问题是子集选取问题。

0-1 背包问题的解空间可以用子集树表示。

在搜索解空间树时,只要其左儿子节点是一个可行节点,搜索就进入左子树。

当右子树中有可能含有最优解时,才进入右子树搜索。

否则,将右子树剪去。

设r是当前剩余物品价值总和,cp是当前价值;bestp是当前最优价值。

当cp+r<=bestp时,可剪去右子树。

计算右子树上界的更好的方法是将剩余物品依次按其单位价值排序,然后依次装入物品,直至
装不下时,再装入物品一部分而装满背包。

例如:对于0-1背包问题的一个实例,
n=4,c=7,p=[9,10,7,4],w=[3,5,2,1]。

这4个物品的单位重量价值分别为[3,2,3,5,4]。

以物品单位重量价值的递减序装入物品。

先装入物品4,然后装入物品3和1.装入这3个物品后,剩余的背包容量为1,只能装的物品2。

由此得一个解为[1,,1,1],其相应价值为22。

尽管这不是一个可行解,但可以证明其价值是最优值的上界。

因此,对于这个实例,最优值不超过22。

在实现时,由Bound计算当前节点处的上界。

类Knap的数据成员记录解空间树中的节点信息,以减少参数传递调用所需要的栈空间。

在解空间树的当前扩展节点处,仅要进入右子树时才计算上界Bound,以判断是否可将右子树剪去。

进入左子树时不需要计算上界,因为上界预期父节点的上界相同。

三、回溯法实现代码:
#include ""
#include <iostream>
using namespace std;
template<class Typew,class Typep>
class Knap
{
template<class Typew,class Typep>
friend Typep Knapsack(Typep [],Typew [],Typew,int);
private:
Typep Bound(int i);
void Backtrack(int i);
Typew c; D = i;
Q[i-1].d = * p[i]/w[i];
P += p[i];
W += w[i];
}
if(W <= c)D];
[i] = w[Q[i-1].ID];
}
= 0;
= 0;
= c;
= n;
= 0;
求找一n
元向量(x1,x2,…,xn,), xi∈{0,1}, ? ∑ wi xi≤c,且∑ vi xi达最大.即一个特殊的整数规划问题。

二、分支限界法步骤思想:
首先,要对输入数据进行预处理,将各物品依其单位重量价值从大到小进行排列。

在优先队列分支限界法中,节点的优先级由已装袋的物品价值加上剩下的最大单位重量价值的物品装满剩余容量的价值和。

算法首先检查当前扩展结点的左儿子结点的可行性。

如果该左儿子结点是可行结点,则将它加入到子集树和活结点优先队列中。

当前扩展结点的右儿子结点一定是可行结点,仅当右儿子结点满足上界约束时才将它加入子集树和活结点优先队列。

当扩展到叶节点时为问题的最优值。

例如:0-1背包问题,当n=3时,w={16,15,15}, p={45,25,25}, c=30。

优先队列式分支限界法:处理法则:价值大者优先。

{}—>{A}—>{B,C}—>{C,D,E}—>{C,E}—>{C,J,K}—>{C}—>{F,G}—>{G,L,M}—>{G,M}—>{G}—>{N,O}—>{O}—>{}。

三、分支限界法解决0-1背包问题实现代码:
D = i;
Q[i-1].d = *p[i]/w[i];
P += p[i];
W += w[i];
}
if(W<=c)
{
return P;D];
[i] = w[Q[i-1].ID];
}
= 0;
= 0;
= c;
= n;
D] = [j];
}
delete Q;
delete [];
delete [];
delete [];
return bestp;
}
template<class Type>
void BubbleSort(Type a[],int n) {
//记录一次遍历中是否有元素的交换 bool exchange;
for(int i=0; i<n-1;i++)
{
exchange = false ;
for(int j=i+1; j<=n-1; j++)
{
if(a[j]<=a[j-1])
{
Swap(a[j],a[j-1]);
exchange = true;
}
}
//如果这次遍历没有元素的交换,那么排序结束 if(false == exchange)
{
break ;
}
}
}
template <class Type>
inline void Swap(Type &a,Type &b)
{
Type temp = a;
a = b;
b = temp;
}
四、程序运行结果:
五、分支限界法解决0-1背包问题复杂度分析:
时间复杂度为:O(2^n);空间复杂度:O(n2^n)。

六、回溯法与分支限界法分析比较:
这两种算法都得到了验证,运行结果证明了算法设计是可行的。

通过对O-1背包问题的算法设计及时间复杂度分析可以看出:无论采用回溯法还是分支限界法,都是在已知约束条件下求解最大值建立数学模型算法实现的过程;但算法具体实现和数据结构的建立要用到递归和栈操作。

比较回溯法和分支限界法,前者的时间复杂度高于后者,从耗费上而言优于后者。

对于回溯法,能够获得最优解,时间复杂度较高,判断右子树时,按效率密度vi/wi对剩余对象排序;对于分支限界法:速度较快,易求解,不过占用的内存较大,效率不高。

成绩单。

相关主题