文章目录

  • 1.问题阐述
  • 2.基本步骤
  • 3.代码实现
  • 4.结果分析
  • 5.参数设置
  • 5.1改变城市序列
  • 5.2固定城市坐标,改变种群数量
  • 5.3固定城市坐标,改变交叉概率
  • 5.4固定城市坐标,改变变异概率
  • 5.5固定城市坐标,改变迭代次数
  • 6.小结


1.问题阐述

  旅行商问题是一个组合优化问题,有许多算法都可解决,比如遗传算法,蚁群算法等。这里将用遗传算法解决旅行商问题。但遗传算法基于二进制编码的交叉和变异操作,对旅行商问题中的城市序列并不适用,用随机取点交换城市序列的方法较合适。

2.基本步骤

  1. 初始化种群个数、交叉概率、变异概率、城市数量等参数值以及适应度函数
  2. 选择。轮盘赌操作随机选择,并保存当代最佳个体。
  3. 交叉。确定城市序列后,随机选择某一个城市序列, 随机选择一个交叉位,点对交换城市。
  4. 变异。随机产生两个数,当随机数小于变异概率,两个数对应的城市交换。
  5. 迭代更新适应度,记录每一次最短路径。将最短路径输出并绘图。

3.代码实现

  初始化种群个数、交叉概率、变异概率、城市数量等参数值并随机生成城市序列:

N=25;               %%城市的个数
M=100;               %%种群的个数
ITER=2000;               %%迭代次数
%C_old=C;
m=2;                %%适应值归一化淘汰加速指数
Pc=0.8;             %%交叉概率
Pmutation=0.05;       %%变异概率
%%生成城市的坐标
pos=randn(N,2);
%%生成城市之间距离矩阵
D=zeros(N,N);
for i=1:N
    for j=i+1:N
        dis=(pos(i,1)-pos(j,1)).^2+(pos(i,2)-pos(j,2)).^2;
        D(i,j)=dis^(0.5);
        D(j,i)=D(i,j);
    end
end
%%生成初始群体
popm=zeros(M,N);
for i=1:M
    popm(i,:)=randperm(N);%随机排列,比如[2 4 5 6 1 3]
end
%%随机选择一个种群
R=popm(1,:);
figure(1);
scatter(pos(:,1),pos(:,2),'rx');%画出所有城市坐标
axis([-3 3 -3 3]);              % 横纵坐标均从-3到3
figure(2);
plot_route(pos,R);      %%画出初始种群对应各城市之间的连线,当前路径
axis([-3 3 -3 3]);

初始化种群及其适应函数:

%%初始化种群及其适应函数
fitness=zeros(M,1);%M=100
len=zeros(M,1);
for i=1:M%计算每个染色体对应的总长度
    len(i,1)=myLength(D,popm(i,:));
end
maxlen=max(len);%最大回路
minlen=min(len);%最小回路
fitness=fit(len,m,maxlen,minlen); %m=2为适应值归一化淘汰加速指数
rr=find(len==minlen);%找到最小值的下标,赋值为rr
R=popm(rr(1,1),:);%提取该染色体,赋值为R
for i=1:N
    fprintf('%d ',R(i));%把R顺序打印出来
end
fprintf('\n');

进行选择、交叉、变异操作并更新适应度:

fitness=fitness/sum(fitness);  %某个适应度/总体适应度
distance_min=zeros(ITER+1,1);  %%各次迭代的最小的种群的路径总长
nn=M; %种群数量M=100
iter=0;
while iter<=ITER %ITER=2000迭代次数
    fprintf('迭代第%d次\n',iter);
    %%选择操作
    p=fitness./sum(fitness);
    q=cumsum(p);%累加
    for i=1:(M-1)
        len_1(i,1)=myLength(D,popm(i,:));
        r=rand;
        tmp=find(r<=q);
        popm_sel(i,:)=popm(tmp(1),:);
    end 
    [fmax,indmax]=max(fitness);%求当代最佳个体
    popm_sel(M,:)=popm(indmax,:);
     %%交叉操作nnper=randperm(M); %随机打乱一个数字序列
 %    A=popm_sel(nnper(1),:);
 %   B=popm_sel(nnper(2),:);
    %%
    for i=1:M*Pc*0.5
        A=popm_sel(nnper(i),:);
        B=popm_sel(nnper(i+1),:);
        [A,B]=cross(A,B);%交叉操作
  %      popm_sel(nnper(1),:)=A;
  %      popm_sel(nnper(2),:)=B; 
         popm_sel(nnper(i),:)=A;
         popm_sel(nnper(i+1),:)=B;
    end
    %%变异操作
    for i=1:M
        pick=rand;
        while pick==0
             pick=rand;
        end
        if pick<=Pmutation %变异概率=0.05
           popm_sel(i,:)=Mutation(popm_sel(i,:));
        end
    end
    maxlen=max(len);
    minlen=min(len);
    distance_min(iter+1,1)=minlen;
    fitness=fit(len,m,maxlen,minlen);
    rr=find(len==minlen);
    fprintf('minlen=%d\n',minlen);
    R=popm_sel(rr(1,1),:);
    for i=1:N
        fprintf('%d ',R(i));
    end
    fprintf('\n');
    popm=[];
    popm=popm_sel;
    iter=iter+1; %迭代次数+1
 end

绘制结果图:

figure(3)
plot_route(pos,R);
axis([-3 3 -3 3]);
figure(4)
plot(distance_min);%最短路径长度变化曲线图

交叉操作函数:

function [A,B]=cross(A,B)
L=length(A);
if L<10
    W=L;
elseif ((L/10)-floor(L/10))>=rand&&L>10
    W=ceil(L/10)+8;
else
    W=floor(L/10)+8;
end
%%W为需要交叉的位数
p=unidrnd(L-W+1);%随机产生一个交叉位置
%fprintf('p=%d ',p);%交叉位置
for i=1:W
    x=find(A==B(1,p+i-1));
    y=find(B==A(1,p+i-1));
    [A(1,p+i-1),B(1,p+i-1)]=exchange(A(1,p+i-1),B(1,p+i-1));
    [A(1,x),B(1,y)]=exchange(A(1,x),B(1,y));
end

变异函数:

function a=Mutation(A)
index1=0;index2=0;
nnper=randperm(size(A,2));
index1=nnper(1);
index2=nnper(2);
%fprintf('index1=%d ',index1);
%fprintf('index2=%d ',index2);
temp=0;
temp=A(index1);
A(index1)=A(index2);
A(index2)=temp;
a=A;
end

对调函数:

function [x,y]=exchange(x,y)
temp=x;
x=y;
y=temp;
end

适应度函数:

function fitness=fit(len,m,maxlen,minlen)
fitness=len;
for i=1:length(len)
    fitness(i,1)=(1-(len(i,1)-minlen)/(maxlen-minlen+0.0001)).^m;
end

4.结果分析

遗传算法求解旅行商问题Java 遗传算法 旅行商_遗传算法求解旅行商问题Java


在迭代2000次后,输出最短路径城市序列。 最短路径迭代表


遗传算法求解旅行商问题Java 遗传算法 旅行商_交叉概率_02

遗传算法求解旅行商问题Java 遗传算法 旅行商_最短路径_03


  由表和曲线图可知最短路径在43次的迭代后达到最优。 最终群体中每个个体所经城市序列

遗传算法求解旅行商问题Java 遗传算法 旅行商_遗传算法求解旅行商问题Java_04


  第15个个体发生变异,其第20和第22个城市换了顺序。

5.参数设置

5.1改变城市序列

1

遗传算法求解旅行商问题Java 遗传算法 旅行商_交叉概率_05

2

遗传算法求解旅行商问题Java 遗传算法 旅行商_迭代_06

3

遗传算法求解旅行商问题Java 遗传算法 旅行商_最短路径_07

4

遗传算法求解旅行商问题Java 遗传算法 旅行商_最短路径_08

5

遗传算法求解旅行商问题Java 遗传算法 旅行商_迭代_09

6

遗传算法求解旅行商问题Java 遗传算法 旅行商_遗传算法求解旅行商问题Java_10

6次验证数据表

遗传算法求解旅行商问题Java 遗传算法 旅行商_交叉概率_11

分析:

  当随机取不同城市序列时,输出最短路径大致在16-20区间内,达最短路径迭代次数在300-800左右区间内,运行时间30-40左右。值得一提的是,第4次验证时迭代输出的最短路径并不是实际最短路径,说明遗传算法会陷入局部最优,导致找到的路径不是全局最短。

5.2固定城市坐标,改变种群数量

1,M=20

遗传算法求解旅行商问题Java 遗传算法 旅行商_遗传算法求解旅行商问题Java_12

2,M=40

遗传算法求解旅行商问题Java 遗传算法 旅行商_最短路径_13

3,M=50

遗传算法求解旅行商问题Java 遗传算法 旅行商_迭代_14

4,M=80

遗传算法求解旅行商问题Java 遗传算法 旅行商_交叉概率_15

5,M=100

遗传算法求解旅行商问题Java 遗传算法 旅行商_交叉概率_16

6,M=150

遗传算法求解旅行商问题Java 遗传算法 旅行商_最短路径_17

7,M=200

遗传算法求解旅行商问题Java 遗传算法 旅行商_遗传算法求解旅行商问题Java_18

8,M=300

遗传算法求解旅行商问题Java 遗传算法 旅行商_遗传算法求解旅行商问题Java_19


遗传算法求解旅行商问题Java 遗传算法 旅行商_最短路径_20


分析:

  当固定城市坐标,改变种群数量,种群数量过小时,输出的最短路径较长,迭代得到的最短路径次数大,说明算法搜索能力不够,效率较低,且较难找到实际最短路径;种群数量过大时,运行时间较长,迭代达到最优次数逐渐下降,最短路径收敛趋势加快,易陷入局部最优,过早得到最短路径。

  因此,种群数量影响算法搜索能力和效率,种群不宜过大也不宜过小,取40-100左右,得到最短路径较小,本例中取M=80最佳,最短路径达最优。

5.3固定城市坐标,改变交叉概率

1,Pc=0.1

遗传算法求解旅行商问题Java 遗传算法 旅行商_最短路径_21

2,Pc=0.2

遗传算法求解旅行商问题Java 遗传算法 旅行商_遗传算法求解旅行商问题Java_22

3,Pc=0.4

遗传算法求解旅行商问题Java 遗传算法 旅行商_遗传算法求解旅行商问题Java_23

4,Pc=0.5

遗传算法求解旅行商问题Java 遗传算法 旅行商_迭代_24

5,Pc=0.8

遗传算法求解旅行商问题Java 遗传算法 旅行商_遗传算法求解旅行商问题Java_25

6,Pc=1.0

遗传算法求解旅行商问题Java 遗传算法 旅行商_最短路径_26

7,Pc=1.5

遗传算法求解旅行商问题Java 遗传算法 旅行商_迭代_27


遗传算法求解旅行商问题Java 遗传算法 旅行商_迭代_28


分析:

  交叉概率在0.4-0.8较合适,当交叉概率小于0.4,大于0.8,最短路径收敛较慢,且陷入局部最优;当交叉概率大于1.5,最短路径变化曲线图波动很大,在1500次迭代中无法稳定收敛,1500次后才逐渐收敛,搜索效率很低,因此交叉概率不宜大于1。

  交叉概率影响了种群参加交配的染色体平均数目pc×N,交叉概率越大,参加交配的染色体越多,越难以收敛找到最优解。本例中取Pc=0.4有全局最短路径。

5.4固定城市坐标,改变变异概率

1,Pm=0.001

遗传算法求解旅行商问题Java 遗传算法 旅行商_迭代_29

2,Pm=0.005

遗传算法求解旅行商问题Java 遗传算法 旅行商_最短路径_30

3,Pm=0.01

遗传算法求解旅行商问题Java 遗传算法 旅行商_交叉概率_31

4,Pm=0.05

遗传算法求解旅行商问题Java 遗传算法 旅行商_遗传算法求解旅行商问题Java_32

5,Pm=0.1

遗传算法求解旅行商问题Java 遗传算法 旅行商_最短路径_33

6,Pm=0.3

遗传算法求解旅行商问题Java 遗传算法 旅行商_最短路径_34

7,Pm=0.5

遗传算法求解旅行商问题Java 遗传算法 旅行商_迭代_35

遗传算法求解旅行商问题Java 遗传算法 旅行商_遗传算法求解旅行商问题Java_36


分析:

  当变异概率过小时,最短路径收敛很慢,曲线波动较大;;当变异概率过大时,基因变异数量变多,最短路径变化波动很大,最短路径难以收敛。

  变异概率决定进化过程中群体发生变异的基因的平均数,本例中取pm=0.01有较短路径,当pm>0,01,搜索又能力变差。

5.5固定城市坐标,改变迭代次数

1,迭代次数=500

遗传算法求解旅行商问题Java 遗传算法 旅行商_迭代_37

2,迭代次数=1000

遗传算法求解旅行商问题Java 遗传算法 旅行商_遗传算法求解旅行商问题Java_38

3,迭代次数=1500

遗传算法求解旅行商问题Java 遗传算法 旅行商_迭代_39

4,迭代次数=2000

遗传算法求解旅行商问题Java 遗传算法 旅行商_遗传算法求解旅行商问题Java_40

5,迭代次数=3000

遗传算法求解旅行商问题Java 遗传算法 旅行商_最短路径_41


遗传算法求解旅行商问题Java 遗传算法 旅行商_遗传算法求解旅行商问题Java_42


分析:

  迭代次数过小,难以收敛到最优,最短路径曲线多波动;当迭代次数增大,收敛速度加快,曲线波动小;迭代次数过大,最短路径过早收敛,难以得到全局最短路径。本例中,取迭代2000次较合适,可以找到全局最优解。

6.小结

  • 种群规模会影响算法搜索能力和效率,种群规模过大搜索能力和效率将下降,因此种群规模不宜过小也不宜过大,取40-100较合适。
  • 交叉概率决定了进化过程种群参加交配的染色体平均数目。取0.4-0.8较合适。
  • 变异概率决定进化过程中群体发生变异的基因的平均数,若发生变异的基因过多,则算法难以收敛。取0.05-0.1较合适。
  • 迭代次数影响算法收敛速度。取1000-2000较合适。

  旅行商问题,是组合优化问题。当利用遗传算法解决时,交叉和变异操作不适用一般遗传算法的染色体编码解码方式,而是利用随机选取交叉点交换实现交叉,交换城市序列的位置来实现变异。不同参数的设置对搜索能力以及能否找到全局最优解有较大影响,所以设置参数时,应多考虑合理性。