染色体编码方式:有两种,在后面局部搜索算子中我用的不带分隔的染色体编码方式
1.带分隔的01230450670
每一个单元格代表一条染色体
2.不带分隔4532167——在matlab中我用元胞数组来实现
如下面这两张图:客户个数:20 种群规模:zaiyoutu
仅有载重约束 没有时间窗约束
在右图中每一个单元格代表一条路径
生成不带分割的染色体代码我会再重新写一篇文章
一、2-opt
%输入nowDist 距离矩阵
%输入初始种群Popu
% 通过2-opt算子进行局部搜索得到新的种群 %路径内
%随机选择一个配送路线,然后在该路线中随机选择两个客户点,
%对这两个客户点之间的客户序列进行反转。(并未随机)
function opt2_Chromes=opt2_function1(Popu,nowDist)
[pops,~]=size(relocate2_Chromes);
Chromes=relocate2_Chromes;
for j=1:pops
Chrome=Chromes{j,:};%取出第i条染色体
midroutes=cell(1,1);
for k=1:size(Chrome,1)%依次选取该染色体的全部路径
route=cell2mat(Chrome(k,:));
midroutes{1,k}=route;
w=2;
for i=1:size(route,2)-1
for s=i+1:size(route,2)
reverse=fliplr(route(i:s));
if i==1
if s==size(route,2)
midroute=reverse;
else
midroute=[reverse,route(s+1:end)];
end
else
if s==size(route,2)
midroute=[route(1:i-1),reverse];
else
midroute=[route(1:i-1),reverse,route(s+1:end)];
end
end
midroutes{w,k}=midroute;
w=w+1;
end
end
end
%计算所有的route的fitness,与原来的chrome中的Route对比,如果更优就代替。
Fits=cell(1,1);%midroutes{w,k}有很多列
for q=1:size(midroutes,2)
A=midroutes(:,q);
A(cellfun(@isempty,A))=[];
outfitnesses=fit_routes2(A,nowDist);
[val,idx]=min(outfitnesses);
Fits{q,1}=outfitnesses(1,1)-val;%原始路径的目标值-最小的值
Fits{q,2}=idx;
end
[~,idx]=max(cell2mat(Fits(:,1)));
Route=cell2mat(midroutes(Fits{idx,2},idx));
Chrome{idx,:}=Route;
Chromes{j,:}=Chrome;
end
opt2_Chromes=Chromes;
end
二、2-opt*
%输入nowDist 距离矩阵
%demands,cap
%输入种群opt2_Chromes
% 通过2-opt*算子进行局部搜索得到新的种群 %路径间
%随机选择两条配送路线,然后在两条路径分别取1个交换位置,
%将第一条路径位置之后的所有顾客节点与第2条路径交换位置之后的所有顾客节点互换
function opt_2Chromes=opt2_function2(opt2_Chromes,nowDist,demands,cap)
[pops,~]=size(opt2_Chromes);
Chromes=opt2_Chromes;
for j=1:pops
Chrome=Chromes{j,:};%取出第j条染色体
Q=randperm(size(Chrome,1),2);%选两条路径 %选两条路径所有的组合方式Q=nchoosek(1:size(Chrome,1),2)
route1=cell2mat(Chrome(Q(1),:));
route2=cell2mat(Chrome(Q(2),:));
midroutes1=cell(1,1);
midroutes1{1,:}=route1;%保留初始路径1
midroutes2=cell(1,1);
midroutes2{1,:}=route2;%保留初始路径2
w=2;
for i=1:size(route1,2)-1
for k=1:size(route2,2)-1
mid1=route1(i+1:end);
mid2=route2(k+1:end);
midroute1=[route1(1:i),mid2];
midroute2=[route2(1:k),mid1];
result1=Result2(demands,cap,midroute1);
result2=Result2(demands,cap,midroute2);
if result1==1&&result2==1%判断交换两点后的两段路径是否可行(满足载重约束)
midroutes1{w,:}=midroute1;
midroutes2{w,:}=midroute2;
w=w+1;
end
route1=cell2mat(Chrome(Q(1),:));
route2=cell2mat(Chrome(Q(2),:));
end
end
%计算所有两点交叉可能出现的路径的目标值
outfitness1=fit_routes2(midroutes1,nowDist);
outfitness2=fit_routes2(midroutes2,nowDist);
outfitnesses=outfitness2+outfitness1;
[~,idx]=min(outfitnesses);
Route1=cell2mat(midroutes1(idx,:));
Route2=cell2mat(midroutes2(idx,:));
Chrome{Q(1),:}=Route1; %路径中目标值最小的替换原本的
Chrome{Q(2),:}=Route2;
Chromes{j,:}=Chrome;
end
opt_2Chromes=Chromes;
end
三、exchange算子
路径内
%输入nowDist 距离矩阵
%输入初始种群Popu,
% 通过两点交换算子(路径内)进行局部搜索得到新的种群
%路径内:随机选择一个配送路线,然后在该路线中随机选择两个客户点,交换客户点位置。
function exchange1_Chromes=exchange1_function(Popu,nowDist)
[pops,~]=size(or_optChromes);
Chromes=or_optChromes;
for j=1:pops
Chrome=Chromes{j,:};
a=randperm(size(Chrome,1),1);%选第a条路径
route=cell2mat(Chrome(a,:));%随机选取出一条路径
%把这条路径中可能出现的两点交换后的路径都储存下来,
%因为在路径内交换所以载重约束是满足的,
%然后计算目标值,得到最小的值对应的路径替换该染色体的原路径。
if size(route,2)~=1 %避免出现某个路径只有一个客户时交换不了
midroute=cell(1,1);
midroute{1,:}=route;
w=2;
for i=1:size(route,2)-1
for k=i+1:size(route,2)
mid=route(i);
route(i)=route(k);
route(k)=mid;
midroute{w,:}=route;
w=w+1;
route=cell2mat(Chrome(a,:));
end
end
%计算所有两点交叉可能出现的路径的目标值
outfitnesses=fit_routes2(midroute,nowDist);
[~,idx]=min(outfitnesses);
Route=cell2mat(midroute(idx,:));
Chrome{a,:}=Route; %路径中目标值最小的替换原本的
Chromes{j,:}=Chrome;
end
end
exchange1_Chromes=Chromes;
end
路径间
%输入nowDist 距离矩阵
%输入种群exchange1_Chromes
% 通过两点交换算子(路径间)进行局部搜索得到新的种群
%路径间:首先随机选择两条配送路线,因为在路径间,所以要判断交换后路径是否可行
%然后在每一条路径中分别随机选择一个客户点,交换两个客户点的位置。
function [exchange2_Chromes,midroute1,midroute2]=exchange2_function(exchange1_Chromes, nowDist,demands,cap)
[pops,~]=size(exchange1_Chromes);
Chromes=exchange1_Chromes;
for j=1:pops
Chrome=Chromes{j,:};
Q=randperm(size(Chrome,1),2);%选两条路径
route1=cell2mat(Chrome(Q(1),:));
route2=cell2mat(Chrome(Q(2),:));
midroute1=cell(1,1);
midroute2=cell(1,1);
midroute1{1,:}=route1;
midroute2{1,:}=route2;
w=2;
for i=1:size(route1,2)
for k=1:size(route2,2)
mid=route1(i);
route1(i)=route2(k);
route2(k)=mid;
result1=Result2(demands,cap,route1);
result2=Result2(demands,cap,route2);
if result1==1&&result2==1%判断exchange后的路径是否可行(满足载重约束)
midroute1{w,:}=route1;
midroute2{w,:}=route2;
w=w+1;
end
route1=cell2mat(Chrome(Q(1),:));
route2=cell2mat(Chrome(Q(2),:));
end
end
%计算所有两点交叉可能出现的路径的目标值
outfitness1=fit_routes2(midroute1,nowDist);
outfitness2=fit_routes2(midroute2,nowDist);
outfitnesses=outfitness2+outfitness1;
[~,idx]=min(outfitnesses);
Route1=cell2mat(midroute1(idx,:));
Route2=cell2mat(midroute2(idx,:));
Chrome{Q(1),:}=Route1; %路径中目标值最小的替换原本的
Chrome{Q(2),:}=Route2;
Chromes{j,:}=Chrome;
end
exchange2_Chromes=Chromes;
end
四、or-opt
%输入nowDist 距离矩阵
%输入种群Popu
% 通过or-opt算子进行局部搜索得到新的种群
%随机选择一个配送路线,然后在该路线中随机选择一个连续客户点序列,
%将其放在路线中的其他任意位置。
function or_optChromes=or_optfunction(Popu,nowDist)
[pops,~]=size(Popu);
Chromes=Popu;
for i=1:pops
Chrome=Chromes{i,:};
a=randperm(size(Chrome,1),1);%选第a条路径
route=cell2mat(Chrome(a,:));%随机选取出一条路径、or-opt也可以选取最长的路径进行下一步的操作
m=randperm(size(route,2),1)-1;%通过路径长度随机出or-opt所需要的m个连续的顾客
if m~=0
s=0;
w=1;
midroute=cell(1,1);
while s+m<=size(route,2)
partRoute=route(:,s+1:s+m);%m个连续的顾客的路径
route(:,s+1:s+m)=[];
for v=1:length(route)+1 %m个连续的顾客插入各个位置的方案
if v==1
Route=[partRoute,route];
elseif v==length(route)+1
Route=[route(1:v-1),partRoute];
else
Route=[route(1:v-1),partRoute,route(v:end)];
end
midroute{w,:}=Route;
w=w+1;
end
s=s+1;
route=cell2mat(Chrome(a,:));
end
routes=midroute; %计算全部路径方案的目标值,选择最小的
outfitnesses=fit_routes2(routes,nowDist);
[~,idx]=min(outfitnesses);
Route=cell2mat(midroute(idx,:));
Chrome{a,:}=Route; %路径(仍是那几位顾客,所以载重约束是满足的)中目标值最小的替换原本的
Chromes{i,:}=Chrome;
end
end
or_optChromes=Chromes;
end
五、涉及到的两个函数
Result2:
%输入单个路径
%输入demands 每个顾客的需求量
%输入cap 车辆最大载货量
% 判断载重约束
function result=Result2(demands,cap,route)
w=0;
for i=1:length(route)
w=w+demands(route(i));
if w>cap
result=0;
break
end
result=1;
end
end
fit_routes2
%输入nowDist 距离矩阵
%midroute-元胞数组 多个路径
% 计算routes目标函数值
function outfitnesses=fit_routes2(midroute,nowDist)
[pops,~]=size(midroute);
fitnesses=[];
for i=1:pops
midfitness=0;
b=1;
route=midroute{i,:};
route=[0,route,0];
for s=1:length(route)
midfitness=midfitness+nowDist(b,route(s)+1);
b=route(s)+1;
end
fitnesses=[fitnesses,midfitness];
end
outfitnesses=fitnesses';
end
其实这几个局部搜索的算子写代码的过程中有很多相同的地方
这里就不放这些算子详细信息,大家可以自行百度
新手小白,欢迎大家批评指正!!!