计算机算法设计与分析Word下载.docx

上传人:b****5 文档编号:21649183 上传时间:2023-01-31 格式:DOCX 页数:28 大小:196.42KB
下载 相关 举报
计算机算法设计与分析Word下载.docx_第1页
第1页 / 共28页
计算机算法设计与分析Word下载.docx_第2页
第2页 / 共28页
计算机算法设计与分析Word下载.docx_第3页
第3页 / 共28页
计算机算法设计与分析Word下载.docx_第4页
第4页 / 共28页
计算机算法设计与分析Word下载.docx_第5页
第5页 / 共28页
点击查看更多>>
下载资源
资源描述

计算机算法设计与分析Word下载.docx

《计算机算法设计与分析Word下载.docx》由会员分享,可在线阅读,更多相关《计算机算法设计与分析Word下载.docx(28页珍藏版)》请在冰豆网上搜索。

计算机算法设计与分析Word下载.docx

此问题更形式化的描述为:

给定c0,wi0,pi0,i=1,2,...,n,要求找出一个n元0/1向量(x1,x2,…,xi,…,xn),xi

{0,1},i=1,2,...,n,使得

,且

达到最大。

因此,0/1背包问题是一个特殊的整数规划问题,其数学模型表示如下:

Max

s.t.

2.问题的应用背景

0/1背包问题是当前组合优化领域研究的一个热点和难点问题,其实质就是组合优化问题,即如何在有效的空间内装载更多的物品,实现背包中物品价值的最大化。

0/1背包问题是一个特殊的整数规划问题,其最终目标是寻求一种最优的分配策略以获得物品最大的价值量。

形象化说,给出一系列可以进行的操作P,每种操作都可以获得相应的价值V,但是进行每一种操作都必须付出相应的代价C,然后求出在总代价不超过给定阈值时可以获取的最大价值。

0/1背包问题在现实生活中有着广泛的应用,如下料问题、贷款组合优化问题、项目选择问题等都可以转换为0/1背包问题,即这些问题都可以转换为整数线性规划问题。

因此,研究0/1背包问题高效求解算法,无论是在理论上还是在实际应用中都具有一定的价值和意义。

3.求解0/1背包问题的常用算法

目前,求解0/1背包问题的算法主要有确定性算法和近似算法两大类,确定性算法有分支限界法、动态规划法、回溯法等;

近似算法有贪心算法、遗传算法、蚁群算法等。

一般来讲,确定性算法只能在短时间内求解小规模的0/1背包问题,而不能快速地求解大规模的0/1背包问题,因此其实用性常常受到问题规模的限制;

而近似算法往往只能求解问题的近似解,有时所求得的解的质量不如人意。

本节首先对求解0/1背包问题的常用算法进行简要的阐述,然后重点对回溯法和分支限界法求解一维0/1背包问题进行着重分析,并用Java语言在MyEclipse8.0平台下编程实现。

3.1遗传算法

遗传算法(GeneticAlgorithms,GAs)是由JohnH.Holland及其学生于20世纪60年代末70年代初提出的一种通过模拟生物进化和遗传选择过程来搜索最优解的智能优化方法。

基本GAs算法的步骤一般为:

确定编码方式及取值范围;

初始化染色体的个数,并随机产生所有的染色体;

计算个体的适应度;

经过遗传算子操作,进行遗传迭代求解。

0/1背包问题的遗传算法求解策略如下:

将物品Wi按单位重量价值(pi/wi)由大到小排序;

依据0/1背包问题的定义(见第1节),则放入背包的总重量为w=

,总价值为p=

f[n]存放目标函数值,即个体的适应度,t[n]存放每个个体的约束条件值。

(1)产生初始种群,并计算每个个体的适应度值和其对应的约束条件值(即为在染色体中选取的物品的重量),比较初始种群中各个个体的适应度。

选择最大者所对应的个体作为第一代最优个体,并记录该个体以及它的适应度和约束条件值;

(2)计算每个个体的选择概率

(3)利用轮盘赌法进行个体选择;

(4)进行交叉运算,随即选择一对个体产生一对有效交叉位置进行交叉运算,并计算新产生的个体的适应度值和约束条件值。

如果新产生的个体重量大于背包容量,则对新产生的个体进行修正,放弃在一个个体中的一个物品,增加另一个个体的一个物品使其重量小于背包重量;

(5)进行变异操作,如果一个个体的一个基因为1,则变为0;

如果是0则变为1,重新计算该个体的适应度值和约束条件值;

(6)选取具有最大值的适应度个体,如果其适应度大于当前的最优值的适应度,则更新当前的最优值为选取的个体,更新当前最优值的约束条件和迭代次数;

(7)循环迭代直到迭代次数超过设定最大值。

分析可知,算法的时间复杂度为O(t*n2),其中t为迭代次数,n为种群大小。

在众多近似算法中,遗传算法是求解0/1背包问题的一个较好算法:

①在求解0/1背包问题时,由于遗传算法的进化特性,使得它在解的搜索过程中不需要了解0/1背包问题的内在性质,遗传算法可以处理任意形式的目标函数和约束,无论是线性的还是非线性的,离散的还是连续的,甚至是混合的搜索空间;

②遗传算法在选择、交叉和变异的过程中,都存在对每一个体进行处理的可能。

若遗传算法每一代对群体规模为n的个体进行操作,实际上处理了大约O(n3)个模式,具有很高的并行性,因而具有显著的搜索效率;

③遗传算法对于各种特殊问题可以提供极大的灵活性来混合构造领域独立的近似,从而保证算法的有效性;

④遗传算法的基本思想简单,运行和实现步骤规范,便于具体使用。

3.2模拟退火算法

模拟退火(SimulatedAnnealing,SA)算法是一种随机的全局寻优算法,其思想源于物理退火过程与组合优化问题之间的相似性,最早由Metropolis于1953年提出,1983年Kirkpatrick等将其应用于组合优化问题。

模拟退火算法求解0/1背包问题的过程如下:

(1)解空间

(2)目标函数

(3)产生新解

随机选取物品Wi,若Wi不在背包中,则将其直接放入背包中,或同时从背包中随机取出另一物品Wj;

若Wi已在背包中,则将其取出,并同时随机装入另一物品Wj。

(4)背包的价值差和重量差

根据上述新解产生的3种可能,相应的背包价值差为:

相应的背包重量差为:

其中

为当前状态下背包重量w的增量。

(5)接受准则

由于0/l背包问题是个有约束的最优化问题,所以通常采用扩充的Metropolis准则

其中t为温度控制参数。

在算法实现过程中,其退火温度t控制着求解过程向最小值的优化方向进行,同时又以概率P来接收劣质解,因此模拟退火算法可以跳出局部极小值点。

只要初始温度足够高、退火过程足够慢,算法就能收敛到全局最优解。

3.3蚁群算法

蚁群算法是由DorigoM.等人依据模仿真实的蚁群行为而提出的一种模拟进化算法。

蚂蚁之间是通过一种称为信息素(Pheromone)的物质传递信息的,蚂蚁能够在经过的路径上留下该种物质,而且能够感知这种物质的存在及其强度,并以此来指导自己的运动方向。

因此,由大量蚂蚁组成的集体行为便表现出一种信息正反馈现象:

某一条路径上走过的蚂蚁越多,该路径上留下的信息素就越多,则后来者选择该路径的概率就越大。

蚂蚁之间就是通过这种信息素的交流,搜索到一条从蚁巢到食物源的最短路径。

将这一问题的核心思想运用到0/1背包问题求解中即是,在某一物品上聚集的信息素越多,则该物品被选择的概率就越大。

就蚁群算法而言,当处理的数据比较小时,其具有很快的收敛速度,而随着数据规模的增大,算法的收敛速度明显降低。

假设有m只蚂蚁,n+1个城市,第0个城市代表背包,第1~n个城市代表各个物品,把第0个城市看作蚂蚁的寻优起点。

令nij=pi/wi表示蚂蚁从城市i转移到城市j的期望程度,这样价值越高同时重量越小的物品对蚂蚁的吸引就越大。

令ij表示路径中留下的信息素强度任,任一只蚂蚁k由城市i转移到城市j的概率可设为:

其中表示路径上的信息量对蚂蚁选择路径所起的作用大小,为吸引度的重要性。

每只蚂蚁从寻优起点出发只需一步就可到达1~n当中任意一个食物源,所以上式中有(i=1,2,..,n)。

寻优过程由多只蚂蚁进行,当每只蚂蚁以较大的概率选中食物源i时,如果有

,则变量xi将加1;

否则给从i到j的路径以罚值,以使后续的蚂蚁不再选择本路径。

当所有节点都受罚以后将结束一次求解过程,然后记录最优解,更新信息素。

更新的公式可为:

上式中k为正常数,为挥发系数,xj为经过该路径的蚂蚁数量。

蚁群算法求解0/l背包问题的过程如下:

(1)初始化:

即将任意两个城市之间的道路上的信息素赋一个初值;

(2)搜索:

让若干只蚂蚁根据信息素和距离选择城市;

(3)每到一个新城市进行信息素局部更新;

(4)所有蚂蚁完成回路后进行全局信息素更新;

(5)记录最优路径,返回步骤

(2)循环直到满足退出条件。

蚁群算法是近年来发展起来的一种随机算法,已经证明可以有效解决背包问题。

但是蚁群算法的收敛性证明尚处于初步阶段,缺乏完善的理论基础,并且在减少寻优计算量和缩短算法运行时间方面,有待进一步改进。

3.4贪心算法

贪心算法(GreedyAlgorithm,GA)是一种改进了的分级处理算法,根据某个优化目标保证每一步都有局部最优解。

贪心算法是从局部最优出发,最终得到整体最优。

贪心算法每次只考虑一步,每一步数据的选取都必须满足局部最优条件。

枚举剩下的数据与当前已经选取的数据组合获得的解中,提取其中能获得最优解的唯一的一个数据,加入结果集合中,直到剩下的数据不能再加入为止。

用贪心法求解问题时应考虑如下几个方面:

(1)候选集合P:

为了构造问题的解决方案,假设有一个候选集合P可以作为问题的可能解,即问题的最终解均取自于候选集合P;

(2)解集合S:

随着贪心选择的进行,解集合S不断扩展,直到构成一个满足问题的完整解;

(3)解决函数:

检查解集合S是否构成问题的完整解;

(4)选择函数:

即贪心策略,这是贪心法的关键。

它指出哪个候选对象最有希望构成问题的解,选择函数通常和目标函数有关;

(5)可行函数:

检查解集合S中加入一个候选对象是否可行,即解集合扩展后是否满足约束条件。

具体来说,在求解0/1背包问题时,对贪心算法可以使用如下三种策略,以使其得到的解更接近最优解。

具体方案如下:

(1)价值优先策略:

从剩余的物品中选取价值最大的可以装入背包的物品。

此时,价值最大的优先被装入背包,然后装入下一个价值最大的物品,直到不能再装入剩下的物品为止。

(2)重量优先策略:

从剩余的物品中选取重量最小的物品装入背包中,这种策略一般不能得到最优解。

(3)单位价值优先策略:

根据价值/重量的比值,按照每一次选取剩下的物品中比值最大的物品装入背包,直到不能再装入为止。

上述三种策略都不能保证得到最优解,但三种策略相比较而言,第三种策略与最优解相差较小。

如果可以选择物品的一部分,用单位价值策略可以保证得到问题的最优解。

在贪心算法时间复杂度的估算中,由于需要对重量或价值或两者的比值进行排序,所以贪心算法的时间复杂度为O(n*logn),n为物品数量。

3.5动态规划法

动态规划(DynamicProgramming,DP)属于运筹学范畴,是一种求解决策过程最优化的数学方法,20世纪50年代初由R.E.Bellman等人在研究多阶段决策过程的优化问题时提出,把多阶段过程转化为一系列单阶段问题,逐个求解,创立了解决这类过程优化问题的新方法——动态规划法。

动态规划算法是先把问题分成多个子问题(一般地,每个子问题都是互相关联和影响的),再依次研究逐个问题的决策。

决策就是某个阶段的状态确定后,从该状态演变到下一阶段状态的选择。

当全体子问题都解决时,整体问题也随之解决。

用枚举的方法从所有可能的决策序列中去选取最优决策序列可能是较费时的笨拙方法,但利用最优性原理去找出递推关系,再找最优决策序列就可能使得枚举数量大大下降,这就是动态规划方法设计算法的主要思路。

动态规划法求解0/1背包问题的过程如下:

(1)将原问题分解为若干个子问题(一般每个子问题是相互关联和影响的),再依次逐个研究问题的决策,也就是把整个问题的最优解与子问题的局部最优解用递推等式联系起来;

(2)定义边界条件;

(3)把边界条件代入递推公式,逐步求得最优解。

其数学描述为:

设fk(ww)代表背包只装入前k种物品,总重量不超过ww的情况下所具有的最大价值,即:

fk(ww)=Max

,0≤ww≤n

s.t.

,0≤ww≤c

这两个式子分别为0/1背包问题子问题的目标函数和约束条件,不难看出其是满足优化原则的。

当使用DP算法求解0/1背包问题时,可以推导出其递推公式和边界条件:

递推公式:

fk(ww)=Max(fk-1(ww),f(ww-wk)+pk),

边界条件:

分析可知,动态规划算法的时间复杂度为O(n*c),n为物品个数,c为背包容量。

动态规划算法是一种经典的0/1背包问题求解算法,其原理简单、思路清晰、易于实现,但对于较大规模的问题,它并不是一个理想的算法,最重要的原因就是它的维数障碍,即计算和存储量的需要对于状态空间和决策空间的维数的增长呈指数增长关系。

这样惊人的增长速度是计算机难以承受的,这就使得独立使用动态规划方法求解规模较大的背包问题发生了困难,且目前尚没有好的解决办法。

3.6回溯法

3.6.1算法描述

回溯法(BacktrackingAlgorithm,BA)有“通用的解题法”之称,用它可以系统地搜索一个问题的所有解或任一解,是一个既带有系统性又带有跳跃性的搜索算法。

在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点出发搜索解空间树。

算法搜索至解空间树的任一结点时,总是先判断该结点是否肯定不包含问题的解,如果肯定不包含,则跳过对以该结点为根的子树的系统搜索,逐层向其祖先结点回溯;

否则,进入该子树,继续按照深度优先的策略进行搜索。

BA在用来求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。

而BA在用来求问题的任一解时,只要搜索到问题的一个解即可结束。

这种以深度优先的方式系统地搜索问题的解的算法称为回溯法,它适用于解一些组合数较大的问题。

3.6.2算法设计基本思想

在对回溯法的描述过程中,已给出了算法设计的基本思想,于此,只是精炼提出算法的思想。

搜索:

回溯法从根结点出发,按深度优先策略遍历解空间树,搜索满足约束条件的解。

剪枝:

在搜索至树中任一结点时,先判断该结点对应的部分解是否满足约束条件,或者是否超出目标函数的界;

也即判断该结点是否包含问题的解,如果肯定不包含,则跳过对以该结点为根的子树的搜索,即剪枝(Pruning);

否则,进入以该结点为根的子树,继续按照深度优先的策略搜索。

一般来讲,回溯法求解问题的基本步骤如下:

(1)针对所给问题,定义问题的解空间;

(2)确定易于搜索的解空间结构;

(3)以深度优先方式搜索解空间,并在搜索过程中利用Pruning函数剪去无效的搜索。

具体到0/1背包问题,回溯法求解过程为:

(1)根据0/1背包问题的数学描述,其解空间向量可表示为(x1,x2,…,xi,…,xn),xi

{0,1}。

xi=0表示物品未放入背包中,xi=1表示物品已放入背包中。

(2)在定义了解空间后,还应将解空间很好地组织起来,以便可用回溯法搜索整个解空间,通常,我们将解空间组织成树或图的形式。

(3)在确定了解空间的组织结构后,回溯法就从开始结点(根结点)出发,以深度优先的方式搜索整个解空间。

这个开始结点就成为一个活结点,同时也成为当前的扩展结点。

在当前的扩展结点处,搜索向纵深方向移至一个新结点。

这个新结点就成为一个新的活结点,并成为当前扩展结点。

如果在当前扩展结点处不能再向纵深方向移动,则当前的扩展结点就成为死结点,即这个结点不再是一个活结点。

此时,应往回移动(回溯)至最近的一个活结点处,并使这个活结点成为当前的扩展结点。

回溯法即是以这种工作方式递归地在解空间中搜索,直至找到所要求的解或解空间中已无活结点时为止。

3.6.3实例分析

考虑下面的具体实例:

3个物品的重量w={20,15,10},价值p={20,30,25},背包容量c=25。

对于n=3的0/1背包问题,其解空间树是一个完全二叉树,如图1所示。

图1n=3时,0/1背包树的解空间树

我们从图1的根结点A处开始搜索其解空间。

具体搜索过程(如图2所示):

开始时,根结点是唯一的活结点,也是当前的扩展结点。

在这个扩展结点处,我们可以沿纵深方向移至结点B或结点C处。

假设我们选择先移至结点B处,此时结点A和结点B都是活结点,结点B成为当前的扩展结点。

由于选取了w1=20,故在结点B处剩余背包容量r=25-20=5,获取的价值p=20。

从结点B处,我们可以移至结点D或E。

由于移至结点D至少需要w2=15的背包容量,而此时背包仅有的剩余容量r=5,故移至结点D导致一个不可行解(见图2中深色标记),利用剪枝策略剪去该枝。

而搜索至结点E不需要背包容量,因而是可行的,从而我们选择移至结点E。

此时,结点E成为新的扩展结点,结点A、B和E是活结点。

在结点E处,r=5,p=20。

从结点E处,可以沿纵深方向移至结点J或K。

移至结点J导致一个不可行解(见图2中深色标记),而移向结点K时是可行的,于是移至结点K而剪去结点J那枝。

此时,结点K成为一个新的扩展结点。

由于结点K是一个叶结点,故我们得到一个可行解,这个解的相应的价值为p=20。

xi的取值由根结点A到叶结点K的路径所唯一确定,即x=(1,0,0)。

由于在结点K处已不能再向纵深扩展,所以结点K成为了死结点,我们返回到结点E处,此时结点E也没可扩展的结点,即结点E也成了死结点。

以此回溯,直至根结点A再次成为当前的扩展结点,然后,沿右子树的纵深方向移动,直至遍历整个解空间。

算法搜索得到的最优值为55,相应的最优解是从根结点A到结点L的路径(0,1,1),即是相应0/1背包问题的最优解。

程序验证结果如图3所示。

图2n=3时,回溯法求解0/1背包问题搜索过程图3回溯法求解算例结果

分析可知,回溯法利用一定的剪枝策略求解0/1背包问题,算法的时间复杂度为O(n*2n),n为物品的数量。

3.6.4程序代码及实验结果

依据上节对n=3时0/1背包问题搜索过程的分析,按照重量优先策略设计如下程序,并用两个算例进行验证。

3.6.4.1程序代码

packageCADA;

//计算机算法设计与分析(ComputerAlgorithmDesign&

Analysis)

publicclassKnapsack0_1_BT{

privatedouble[]p;

//物品价值

privatedouble[]w;

//物品重量

privateintn;

//物品数

privatedoublec;

//背包容量

privatedoublebestp;

//当前最优价值

privatedoublecp;

//当前价值

privatedoublecw;

//当前重量

privateint[]x;

//记录可选物品的重量

privateint[]cx;

//记录可选物品的价值

publicKnapsack0_1_BT(double[]p,double[]w,doublec){

this.p=p;

this.w=w;

this.n=p.length-1;

this.c=c;

this.bestp=0;

this.cp=0;

this.cw=0;

x=newint[w.length];

cx=newint[p.length];

}

voidKnapsack0_1_BT(){

backtrack(0);

voidbacktrack(inti){

//TODOAuto-generatedmethodstub

if(i>

n){//判断是否到达了叶子节点

if(cp>

bestp){

for(intj=0;

j<

x.length;

j++)

x[j]=cx[j];

bestp=cp;

}

return;

if(cw+w[i]<

=c){//x[i]=1搜索右子树

cx[i]=1;

cw+=w[i];

cp+=p[i];

backtrack(i+1);

cw-=w[i];

cp-=p[i];

cx[i]=0;

//检查左子树

voidprintResult(){

System.out.println("

------------------------------------"

);

-------回溯法求解0/1背包问题---------"

背包容量:

c="

+c);

物品数量:

n="

+n);

System.out.print("

物品重量数组:

"

w={"

w.length;

j++){

System.out.print(w[j]+"

"

}"

System.out.println();

物品价值数组:

p={"

p.length;

System.out.print(p[j]+"

最优价值:

bestp="

+bestp);

选中的物品是:

("

System.out.print(x[j]+"

)"

pub

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

当前位置:首页 > 成人教育 > 自考

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

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