遗传算法求解0/1背包问题

遗传算法(genetic algorithm,GA)是计算数学中用于解决最优化问题的搜索算法,是进化算法的一种。进化算法最初是借鉴了达尔文进化生物学中的一些现象而发展起来的,这些现象包括遗传、突变、自然选择以及杂交等。

遗传算法通常实现方式为一种计算机模拟。对于一个最优化问题,一定数量的候选解(称为个体)可抽象表示为染色体,使种群向更好的解进化。传统上,解用二进制表示(即0和1的串),但也可以用其他表示方法。进化从完全随机个体的种群开始,之后一代一代发生。在每一代中评价整个种群的适应度,从当前种群中随机地选择多个个体(基于它们的适应度),通过自然选择突变产生新的生命种群,该种群在算法的下一次迭代中成为当前种群。

基本的遗传算法以初始种群为起点,经过自然选择交叉突变操作生成新的种群,经过反复更新种群直到寻找到最优解。其计算步骤如下:

  1. 编码:将问题空间转换为遗传空间;
  2. 生成初始种群:随机生成P个染色体;
  3. 种群适应度计算:按照确定的适应度函数,计算各个染色体的适应度;
  4. 选择:根据染色体适应度,按照选择算子进行染色体的选择;
  5. 交叉:按照交叉概率对被选择的染色体进行交叉操作,形成下一代种群;
  6. 突变:按照突变概率对下一代种群中的个体进行突变操作;
  7. 返回第3步继续迭代,直到满足终止条件。

背包问题(Knapsack Problem)是一个典型的组合优化问题,在计算理论中属于NP-完全问题, 其计算复杂度为 O(2n) ,传统上采用动态规划来求解。设 s[i] 是经营活动 i 所需要的资源消耗,C是所能提供的资源总量, v[i] 是人们经营活动i得到的利润或收益,则背包问题就是在资源有限的条件下, 追求总的最大收益的资源有效分配问题。

0/1背包问题的一般提法是:已知n个物品的体积为

size={s1,s2,...,sn},si>0

其价值(或收益)是
value={v1,v2,...,vn},vi>0

背包的容量(contain)假设设为 C ,如何选择哪些物品装入背包可以使得在背包的容量约束限制之内所装物品的价值最大?
更形式地,求解一个有n个元素的集合 {x1,x2,...,xn},xi0,1 ,使得目标函数
f(x1,x2,...,xn)=Σvixi
在条件
ΣsixiC
下最大。

例题1:背包容量为9,物品体积 size={2,3,4,5} ,其价值是 value={3,4,5,7}

方法一:使用动态规划法求解0/1背包问题:
V[i,j] 是前 i 项中取出的装入体积为j的背包中物品的最大价值,这里 0in,0jC 。我们要求的值就是 V[n,C] 。其递推公式为:

V[i,j]=0V[i1,j]max{V[i1,j],V[i1,jsi]}i=0j=0j<sii>0jsi

求解过程:

i0123456789
00000000000
10033333333
20034477777
300344789912
40034578101112

时间复杂度: O(nC) ,空间复杂度 O(C) 。注意这里是伪多项式时间,算法对于输入是指数的。

方法二:使用贪心算法求解0/1背包问题:计算的复杂度降低了很多,但是往往难以得到最优解,有时所得解与最优解相差甚远。
在本例中,物品性价比依次为 {1.5,1.33,1.25,1.4} ,若采用贪心算法,则依次选择物品1和4,总价值只能达到10。
时间复杂度为 O(nlogn)

方法三:使用遗传算法求解0/1背包问题:

  1. 编码:基于背包问题的模型,我们设计了针对于背包问题的染色体编码方法:将待求解的各量 {x1,x2,...,xn} 表示成长为 n 的二进制字符串x[j],j=1,2, …,n。x[j]=0表示物体j不放入背包内,x[j]=1表示物体j放入背包内。例如:1010代表一个解,它表示将第1、3号物体放入背包中,其它的物体则不放入。

  2. 生成初始种群:本例中,群体规模的大小取为4,即群体由4个个体组成,每个个体可通过随机的方法产生。例如:
    a1 = [1, 1, 1, 1]
    a2 = [1, 0, 1, 0]
    a3 = [1, 0, 0, 1]
    a4 = [1, 0, 0, 0]

  3. 种群适应度计算:按照下列公式计算种群中个体适应度:

    TotalSize=Σsixi

    Fitness={ΣvixiΣvixialpha(TotalSizeC)TotalSizeCTotalSize>C

    公式的下半部分即为适应度的惩罚函数,其中参数 alpha>1.0 。在本例中我们取 alpha=2
    a1 = [1, 1, 1, 1], totalSize = 14, totalValue = 19, fit = 9
    a2 = [1, 0, 1, 0], totalSize = 6, totalValue = 8, fit = 8
    a3 = [1, 0, 0, 1], totalSize = 7, totalValue = 10, fit = 10
    a4 = [1, 0, 0, 0], totalSize = 2, totalValue = 3, fit = 3

  4. 选择:我们采用与适应度成正比的概率来确定各个个体复制到下一代群体中的数量。其具体操作过程如下:

    • 先计算出群体中所有个体的适应度的总和 Σf(ai) i=1,2,3,4 ;
    • 其次计算出每个个体的相对适应度的大小 p(ai)=f(ai)/Σf(ai) i=1,2,3,4 。它即为每个个体被遗传到下一代群体中的概率;
    • 每个概率值组成一个区间,全部概率值之和为1;
    • 最后再产生一个0到1之间的随机数,依据该随机数出现在上述哪一个概率区域内来确定各个个体被选中的次数。
      在本例中,
      Σf(ai)=30

      p(a1)=30.00%p(a2)=26.66%p(a3)=33.33%p(a4)=10.00%

      因此 a1=[0,0.3] a2=[0.3,0.5666] a3=[0.5666,0.9] a4=[0.9,1]
      经过4次选择, a3 被选1次, a2 被选2次, a4 落选:
      b1 = [1, 0, 1, 0], totalSize = 6, totalValue = 8, fitValue = 8
      b2 = [1, 0, 0, 1], totalSize = 7, totalValue = 10, fitValue = 10
      b3 = [1, 0, 1, 0], totalSize = 6, totalValue = 8, fitValue = 8
      b4 = [1, 1, 1, 1], totalSize = 14, totalValue = 19, fitValue = 9
  5. 交叉:本例采用单点交叉的方法,其具体操作过程是:

    • 先对群体进行随机配对;
    • 其次随机设置交叉点位置;
    • 最后再相互交换配对染色体之间的部分基因。
      在本例中,
      b1 b4 在第3位后交叉,生成:
      c1 = [1, 0, 1, 1], totalSize = 11, totalValue = 15, fitValue = 11
      c2 = [1, 1, 1, 0], totalSize = 9, totalValue = 12, fitValue = 12
      b2 b3 在第2位后交叉,生成:
      c3 = [1, 0, 1, 0], totalSize = 6, totalValue = 8, fitValue = 8
      c4 = [1, 0, 0, 1], totalSize = 7, totalValue = 10, fitValue = 10
  6. 突变:我们采用基本位变异的方法来进行变异运算,其具体操作过程是:
    • 首先确定出各个个体的基因变异位置;
    • 然后依照某一概率将变异点的原有基因值取反。
      本例中, c1 的第1位发生突变:
      c1 = [0, 0, 1, 1], totalSize = 9, totalValue = 12, fitValue = 12
      c2 = [1, 1, 1, 0], totalSize = 9, totalValue = 12, fitValue = 12
      c3 = [1, 0, 1, 0], totalSize = 6, totalValue = 8, fitValue = 8
      c4 = [1, 0, 0, 1], totalSize = 7, totalValue = 10, fitValue = 10
      至此,我们已经找到了2个最优解 c1 c2

例题2:假设50个物品的体积Size、物体的价值Value和背包的容量C分别为:
Size={ 80,82,85,70,72, 70,66,50,55,25 ,
50,55,40,48,50, 32,22,60,30,32 ,
40,38,35,32,25, 28,30,22,50,30 ,
45,30,60,50,20 , 65,20,25,30,10 ,
20,25,15,10,10 , 10,4, 4, 2, 1 }

Value={ 220,208,198,192,180, 180,165,162,160,158,
155,130,125,122,120 , 118,115,110,105,101,
100,100,98, 96, 95, 90, 88, 82, 80, 77 ,
75, 73, 72, 70, 69, 66, 65, 63, 60, 58,
56, 50, 30, 20, 15, 10, 8, 5, 3, 1}

C=1000,
如何选择哪些物品装入该背包可使得在背包的容量约束限制之内所装物品的总价值最大?
传统算法(回溯法或者动态规划法)所得结果:总价值为3103, 总重量为1000。最大迭代次数为400次。
贪心算法所得结果:总价值为3077 , 总重量为999。
遗传算法所得结果:总价值为3103, 总重量为1000。最大迭代次数为75次。
我们所求得最优解的个体分配情况为:
11010 10111 10110 11011 01111 11101 00001 01001 10000 01000

例题3:用遗传算法求解TSP问题。
旅行商问题(Travelling Salesman Problem,又称为货郎担问题、TSP问题)是一个多局部最优的最优化问题:有n个城市,一个推销员要从其中某一个城市出发,唯一走遍所有的城市,再回到他出发的城市,求最短的路线。也即求一个最短的哈密顿回路。

问题回顾:用遗传算法求解八皇后问题的编码和交叉方式:
编码:染色体的长度取决于皇后的个数,本例中染色体长度即为8。染色体中每个基因所处的位置表示其在棋盘上的行号,基因值表示其所在的列号。例如,染色体4075623,表示第0行皇后放在第4列,第1行皇后放在第0列,第2行皇后放在第7列,等等。八皇后问题中的任意两个皇后不能出现在同列,因此染色体中的基因取值(0~7)不可重复。
交叉:采用单点交叉的方法,先对群体进行随机配对,对于每一对染色体,首先随机选取两点截取一段基因,例如:
01∥24∥3675
12∥30∥4576
然后将这段基因进行交换:
01∥30∥3675
12∥24∥4576
这样生成的两条染色体并不合法,因此要对中间段外的基因进行交换,从而生成合法的染色体:
41∥30∥2675
13∥24∥0576
交叉完成。

在TSP问题中,因为每个城市只能经过一次,所以可采用类似的方式求解。
具体求解方法请参考:
http://blog.5long.me/2015/genetic-algorithm-on-tsp/

  • 21
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
遗传算法是一种基于生物进化机制的优化算法,可以用于解决0/1背包问题。0/1背包问题是一个经典的组合优化问题,它的目标是在给定的一组物品中选择一些物品放入一个背包中,使得这些物品的价值最大,同时不超过背包的容量限制。 在MATLAB中,可以使用genetic algorithm函数来实现遗传算法。具体步骤如下: 1. 定义适应度函数:适应度函数是用来评估每个个体的适应程度,通常是根据个体的目标函数值来计算的。对于0/1背包问题,适应度函数可以定义为背包中所选物品的总价值。 2. 定义变量范围和约束条件:变量范围是指每个个体的取值范围,对于0/1背包问题来说,变量可以定义为一个二进制向量,表示是否选择该物品。约束条件是指个体必须满足的条件,对于0/1背包问题来说,约束条件是背包的容量限制。 3. 设置遗传算法参数:遗传算法有很多参数需要设置,如种群大小、交叉概率、变异概率等等。这些参数的设置会影响算法的收敛速度和效果。 4. 运行遗传算法:调用genetic algorithm函数,输入适应度函数、变量范围、约束条件和算法参数,即可运行遗传算法求解0/1背包问题。 以下是一个MATLAB实现的示例代码: ```matlab % 0/1背包问题遗传算法求解 % 定义适应度函数 function f = fitness(x, w, v, c) f = sum(v.*x); % 物品的总价值 if sum(w.*x) > c % 超出背包容量,惩罚项为负无穷 f = -Inf; end end % 定义变量范围和约束条件 n = 10; % 物品数量 w = randi([1, 10], 1, n); % 物品重量 v = randi([1, 10], 1, n); % 物品价值 c = 50; % 背包容量限制 lb = zeros(1, n); % 变量下界 ub = ones(1, n); % 变量上界 A = []; b = []; % 线性约束条件 Aeq = []; beq = []; % 线性等式约束条件 nonlcon = @(x) deal([], sum(w.*x) - c); % 非线性约束条件 % 设置遗传算法参数 options = gaoptimset('PopulationSize', 100, 'Generations', 50, 'CrossoverFraction', 0.8, 'MutationFcn', {@mutationuniform, 0.05}); % 运行遗传算法 [x, fval] = ga(@(x)fitness(x, w, v, c), n, A, b, Aeq, beq, lb, ub, nonlcon, options); % 输出结果 disp(['选择的物品编号为:', num2str(find(x))]); disp(['背包中所选物品的总价值为:', num2str(fval)]); ``` 在上面的代码中,fitness函数用来计算个体的适应度,其中x为二进制向量,表示是否选择该物品;w和v分别为物品的重量和价值;c为背包的容量限制。 遗传算法的参数通过gaoptimset函数进行设置。在这个例子中,选择种群大小为100,最大迭代次数为50,交叉概率为0.8,变异概率为0.05。 最后,调用ga函数进行求解,得到选择的物品编号和背包中所选物品的总价值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值