0基础开始遗传算法,理论+代码注释解决01背包问题(matlab)

 01背包问题概述

问题:有一个箱子的最大载重量为cap(正整数),同时有n个物品(正整数),每个物品有一个重量(正整数)以及对应的价值。要求n个物品中,任取若干个装入箱内,要求:在保证箱子最大载重量不被超过的情况下,箱子内的物品价值最高。物品i的重量为weighti(i=1,2,...,N),物品i的价值为valuei(i=1,2,...,N),物品i被选择时xi=1,否则xi=0。背包内物品的总重量为

,物品的价值总量为

,如何决定变量的值使背包内物品价值总量为最大。这个问题的数学模型表示如下:

遗传算法解法

遗传算法是一种常见的解决方案。

基本原理(这里借鉴了其他博主的博客版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。原文链接:https://blog.csdn.net/m0_70379869/article/details/126455436)是:

      模拟生物基因遗传的做法,通过编码组成初始群体后,遗传操作的任务就是对群体的个体按照它们对环境适应度(适应度评估)施加一定的操作,从而实现优胜劣汰的过程。通过一代一代的优化,逼近最优化的解(局部最优化解)。

具体算法若干概念如下:

      遗传操作包含四个算子(基本的四个):种群初始化(Population initialization)、选择(select)、交叉(crossover)、变异(mutation)

其他概念包含:编码(Coding)、解码(Decoding)、个体(Individual)等。

基本设置与种群初始化

根据书本:Matlab 智能优化算法:从写代码到算法思想,中给了以下算例,假设箱子最大载重量为1000

首先进行基本设置

close;% 关闭绘图窗口
clear all;% 清除工作区所有变量
clc;%清除command line window 命令行窗口

背包问题初始设置

weight = [80,82,85,70,72,70,82,75,78,45,49,76,45,35,94,49,76,79,84,74,76,63,...
    35,26,52,12,56,78,16,52, 16,42,18,46,39,80,41,41,16,35,70,72,70,66,50,55,25, 50,55,40];%5个物品各自的重量
value  = [200,208,198,192,180,180,168,176,182,168,187,138,184,154,168,175,198,...
    184,158,148,174,135, 126,156,123,145,164,145,134,164,134,174,102,149,134,...
    156,172,164,101,154,192,180,180,165,162,160,158,155, 130,125]; %50个物品对应的价值
max_bagweight = 1000;%背包最大承受重量

决策变量设置

具体理论可以看这一篇博客,以免大家对以下代码中特定名词如染色体,基因看不懂的可以看上文链接

chromlength = length(weight);%使用length长度获取物品的数量,即个体基因个数(染色体长度)
p_crossover = .95; % probability of crossover 交叉概率
p_mutation = .15; %probability of crossover 变异概率
max_iterations = 500; %最大迭代次数,单词iteration意思为迭代
population_sizes = 200;%初始种群规模

构建初始种群

%load population.mat

pop =[];%创建初始种群的空矩阵
for i = 1:population_sizes;
%pop(i,:) = truerand(1,chromlength,0,1);%随机获得初始种群的个体,即染色体
pop=round(rand(population_sizes,chromlength));%破解版matlab需要自行安装truerand组件,不行可以使用这行代码进行种群初始化
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%前面的基本参数已经输入完毕,接下来就是遗传代码的循环迭代来产生新的种群

迭代开始

%遗传算法循环
for k = 1:max_iterations;

个体的淘汰以及适应度计算

在这里我使用精英保留策略,因为我们在种群初始化时会遇到不符合约束的染色体(解),这里我采用了精英保留策略,即不符合约束的解换成当下适应度(目标函数)最高的值,还有另外一种解决不符合约束解的方法:遗传算法求解0-1背包问题(附matlab源代码) (qq.com),微信gzh: 优化算法交流地,文章:遗传算法求解0-1背包问题(附matlab源代码)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%第一步,选择符合约束的个体(染色体)
for i = 1:population_sizes;
    while pop(i,:) * weight' > max_bagweight;%当初始解不符合约束时,染色体上的基因为0
          pop(i,:)=0; 
    end

end


    %适应度计算
    for i = 1:population_sizes;                 %对14个种群计算适应度
         Fit(i) = pop(i,:) * value';
    end
    Fit=Fit';
    maxFit = max(Fit);                          %寻找适应度最大值
    minFit = min(Fit);                          %寻找适应度最小值,即不符合约束的染色体
    Index_of_chromBest = find(Fit==maxFit);%%找路境中与maxFit相等元素的位置
    Index_of_chromworse = find(Fit==minFit);%%找路境中与minFit相等元素的位置
    chromBest = pop(find(Fit==maxFit),:);    %find(Fit==maxFit),寻找fit中最大值索引,对应pop中的行数,然后找到历代最优个体
    %用最优个体替代不符合约束条件的个体

for i=1:population_sizes;
    if sum(abs(pop(i,:)))==0;   %重量超过约束 
            pop(i,:)=chromBest(1,:);
            Fit(i)=maxFit;           
    end
end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

选择:基于轮盘赌的操作

这部分理论知识可以参考这篇文章:轮盘赌选择解析 (附MATLAB代码) (qq.com),微信gzh: MATLAB智能优化算法,文章:轮盘赌选择解析 (附MATLAB代码) 之前我没搞懂为啥要使用累加cumsum函数,看了这部分就了解了什么是轮盘赌以及实现方法。

fitvalue = Fit/sum(Fit); %个体/染色体被选中的概率为书中的Pi
 Pcum = cumsum(fitvalue); %个体适应度的累加
 
 roulette_hands = sort(rand(population_sizes,1));%rand随机产生0到1之间的数;sort对数组元素按升序排列
    fiti = 1;
    newi = 1;
    while newi <= population_sizes;

           if (roulette_hands(newi)) < Pcum(fiti);
            new_population(newi,:) = pop(fiti,:);
            newi = newi + 1;
         else
            fiti = fiti + 1;
         end

    end

交叉

newpop=ones(size(pop));%产生下一代的种群矩阵的初始规模
for i=1:2:(population_sizes-1);%步长为2,是将相邻的两个个体进行交叉                                             

        if(rand<p_crossover);
                cpoint=round(rand*chromlength);%四舍五入到最接近的整数,确定染色体上哪个基因之后的染色体片段需要互换(一维向量的索引值)
                newpop(i,:)=[pop(i,1:cpoint),pop(i+1,cpoint+1:chromlength)];%相邻两个个体的染色体片段开始交叉
                newpop(i+1,:)=[pop(i+1,1:cpoint),pop(i,cpoint+1:chromlength)];
        else
                newpop(i,:)=pop(i,:);
                newpop(i+1,:)=pop(i+1,:);
        end
end

​

变异

for i=1:population_sizes;
                if(rand<p_mutation);
                        mpoint=round(rand*chromlength);   %确定变异点在染色体基因之间  

                        if mpoint<=0;
                           mpoint=1;                         
%变异位置
                        end
                        newpop(i,:)=pop(i,:);
                        if any(newpop(i,mpoint))==0;
                                newpop(i,mpoint)=1;
                        else
                                newpop(i,mpoint)=0;
                        end
                else
                newpop(i,:)=pop(i,:);
        end
end

将新的New population 赋值给initial population

pop=newpop;%新的New population 赋值给initial population
%pop(1,:)=chromBest(1,1);%保留上一代最优个体
trace(k) = maxFit;
end

画图

disp(["该装进背包的物品编号为",[find(chromBest(1,:)==1)]]);                                  %最优个体
disp(["总价值为",num2str(maxFit)]);                                  %最优目标值
figure
plot(trace)
xlabel('迭代次数')
ylabel('目标函数值')
title('适应度进化曲线')

由于遗传算法只能近似最优解,所以多运行几次会出现最优解:

最优目标值为:3966.0
最优分配为:[0 0 0 0 0 0 0 0 0 1 1 0 1 1 0 1 0 0 0 0 0 0 1 1 0 1 1 0 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 1 1 1 1 1 0 1]
背包标签为:[10 11 13 14 16 23 24 26 27 29 30 31 32 33 34 35 37 38 39 40 44 45 46 47 48 50]
  • 19
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值