一文读懂GA遗传算法(原理+案例+源码)
-
编码方式:将问题的解编码为一组染色体,常用二进制编码、实数编码等
-
种群规模:通常设置为50-200个个体,规模过小容易早熟收敛,过大则计算成本增加
-
初始化策略:完全随机生成,或结合启发式信息生成部分优质个体
-
适应度函数设计:直接决定最终结果优劣,需准确反映个体质量
-
最大化问题:适应度 = 目标函数值 -
最小化问题:适应度 = 1/(目标函数值 + ε) 或采用线性变换 -
评价标准:适应度值越高,个体越优秀,生存和繁殖机会越大
-
轮盘赌选择:个体被选概率 = 个体适应度/总适应度,实现简单,但高适应度个体可能垄断 -
锦标赛选择:随机选k个个体,取最优,常用k=2或3 -
排序选择:按适应度排序,基于排名选择,适合适应度差异大的情况 -
精英保留:直接将最优个体复制到下一代,防止优秀基因丢失
-
二进制编码:
-
实数编码:
-
排列编码(如TSP问题):
-
二进制编码:采用位翻转变异,即随机选几位,0变1或1变0 -
实数编码:采用高斯变异、均匀变异,给实数基因添加随机扰动 -
排列编码:采用交换变异、插入变异、逆序变异,需要保持排列约束
-
节拍约束:要求每个工位上的装配操作必须在生产时间节拍内完成; -
优先关系约束:要求装配操作的前序完成后才能加工其后续操作,例如电视机安装必须先装内部元器件后才能封装外壳。



-
一个任务只能分配到一个工位上:

-
任务间的优先级关系约束:

-
各工位时间不得大于生产节拍:

-
各工位分配的任务不能超过总数N:

%% 初始化种群num1=100; %种群规模num2=500; %进化代数num3=20; %选择操作时的最优个体数目pc=0.6; %交叉概率pm=0.05; %变异概率P=zeros(num,num); %记录各任务优先级关系的矩阵[row,col]=size(S);for i=1:row %得到优先级矩阵P(S(i,1),S(i,2))=1;endpop=zeros(num1,num+1);for i=1:num1 %初始化种群使其满足优先级关系while 1 %确定每个种群的第一个任务m=randi(num,'int8');sum=0;for i_=1:numsum=sum+P(i_,m);endif sum==0pop(i,1)=m; %放置第一个任务break;endendfor j=2:num % 确定每个种群后面的任务while 1ff=0;m=randi(num,'int8');for k=1:j-1 %判断所生产的任务前面是否已安排if m==pop(i,k)ff=1;break;endendif ff==1continue;endsum=0;for k=1:j-1 %前面安排的任务中是m前序的数目sum=sum+P(pop(i,k),m);endsum_=0;for i_=1:num %任务m的所有优先前序sum_=sum_+P(i_,m);endif sum_==sumpop(i,j)=m;break;endendendend
function [pop]=fitness_function(pop) %求适应度函数,即求工人数目global ct T[num1,num]=size(pop);for i=1:num1M=0;tt=0;for j=1:num-2tt=tt+T(pop(i,j));if(tt<=ct)&&(tt+T(pop(i,j+1))>ct) %确定每个工人的工作时间在生产节拍内M=M+1;tt=0;endif j==num-2M=M+1;tt=0;endendpop(i,num)=M; %求得的工人数end
function [pop]=select(pop,c) %选择操作[s,t]=size(pop);m=(pop(:,t))';mmax=zeros(1,c);mmin=zeros(1,c);m1=m;num=1;while num<c+1 %取m值大的c个个体[a,mmax(num)]=max(m1);m1(mmax(num))=0;num=num+1;endm2=m;num=1;while num<c+1 %取m值小的c个个体[b,mmin(num)]=min(m2);m2(mmin(num))=a+1;num=num+1;endfor i=1:c %用m值大的样本替代m值小的pop(mmax(i),:)=pop(mmin(i),:);end
function [pop]=cross(pop) %交叉操作global P[s,t]=size(pop);pop1=pop;n=randperm(s); %每次进化种群随机排序for i=1:s-1point=randi(t-1,'int8');%选择一个随机交叉点x1=n(i); %随机取两行交叉x2=n(i+1);mid=pop(x1,1:point); %将x1的左面和x2的左面交换pop(x1,1:point)=pop(x2,1:point);pop(x2,1:point)=mid;a1=pop(x1,1:t-1);a2=pop(x2,1:t-1);%c2为交换后的个体b1=[]; b=[];j_=1;for j=1:point %寻找a1重复元素插入b1len=length(a1);if len==pointbreak;endfor k=point+1:lenif a1(j)==a1(k)b(j_)=k;j_=j_+1;endb1=[b1 a1(k)];endenda1(b)=[]; %删除a1中重复的数据b2=[];b=[];j_=1;for j=1:point %寻找a2重复元素插入b2len=length(a2);if len==pointbreak;endfor k=point+1:lenif a2(j)==a2(k)b(j_)=k;j_=j_+1;endb2=[b2 a2(k)];endenda2(b)=[]; %删除a2中重复的数据if isempty(b1)&&isempty(b2) %将重复元素按优先级插入原编码pop(x1,1:t-1)=a1;pop(x2,1:t-1)=a2;elseif length(a1)==pointc1=[];c2=[];elsec1=a1(point+1:length(a1));c2=a2(point+1:length(a2));%c2为删除重复点后交叉点后半部分数据endfor j=1:length(b1)b=b1(j);len=length(c2);if len==0c2=[c2 b];elseif len==1if P(b,c2(len))==1c2=[b c2];elsec2=[c2 b];endelsefor k=1:lenif P(b,c2(k))==1break;endendif k==1c2=[b c2];elseif k==lenif P(b,c2(len))==1c2=[c2(1:len-1),b,c2(len)];elsec2=[c2 b];endelsec2=[c2(1:k-1),b,c2(k:len)];endendendendfor j=1:length(b2)b=b2(j);len=length(c1);if len==0c1=[c1 b];elseif len==1if P(b,c1(len))==1c1=[b c1];elsec1=[c1 b];endelsefor k=1:lenif P(b,c1(k))==1break;endendif k==1c1=[b c1];elseif k==lenif P(b,c1(len))==1c1=[c1(1:len-1),b,c1(len)];elsec1=[c1 b];endelsec1=[c1(1:k-1),b,c1(k:len)];endendendendpop(x1,1:t-1)=[a1(1:point) c1];pop(x2,1:t-1)=[a2(1:point) c2];endend %进行交叉变异pop=fitness_function(pop); % 计算适应度for i=1:s %新种群与变异前对比取优if pop1(i,t)<pop(i,t)pop(i,:)=pop1(i,:);endend
function [pop]=mutate(pop) %变异操作global P[s,t]=size(pop);pop1=pop;for i=1:s %进行变异point=randi(t-2,'int8'); %随机选择变异点aa=pop(i,1:t-1);b=aa(point);aa(point)=[];len=length(aa);for j=1:lenif P(b,aa(j))==1break;endendif j==1pop(i,1:t-1)=[b aa];elseif j==lenif P(b,aa(len))==1pop(i,1:t-1)=[aa(1:len-1) b aa(len)];elsepop(i,1:t-1)=[aa b];endelsepop(i,1:t-1)=[aa(1:j-1) b aa(j:len)];endend[pop]=fitness_function(pop); % 计算适应度for i=1:s %与变异前比较取优if pop1(i:t)<pop(i,t)pop(i,:)=pop1(i,:);endend
for k=1:num2 % 开始迭代优化计算pop=fitness_function(pop); % 计算适应度pop=select(pop,num3); % 选择操作p2=rand;if p2<=pmpop=mutate(pop); % 变异操作endgen(k)=min(pop(:,num+1));end

最少需要5个工人,任务分配流程:
-
工位一:先分配任务1,完成任务1的时间是1秒,生产节拍为7秒,剩余6秒的时间,可以继续分配任务,可以选择的有任务2和4,选择任务2;此后工作时间6秒,剩余时间1秒,不能进行下一个任务分配,工位一任务分配完成。
-
工位二:先分配任务4,完成时间3秒,剩余时间4秒,后续可分配任务中有任务3,任务5,任务7,只有任务3满足要求可以分配。
-
工位三:分配任务5,完成时间5秒,工位三任务分配完成。
-
工位四:分配任务7,完成时间5秒,工位四任务分配完成。
-
工位五:最后只有任务6没有分配,只能安排任务6,所有任务完成。
工人任务分配和总的花费时间如图所示

总的工作时间:



夜雨聆风