基于遗传算法解决TSP问题(旅行商问题)

1.遗传算法介绍

遗传算法(Genetic Algorithm)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。遗传算法是从代表问题可能潜在的解集的一个种群(population)开始的,而一个种群则由经过基因(gene)编码的一定数目的个体(individual)组成。每个个体实际上是染色体(chromosome)带有特征的实体。染色体作为遗传物质的主要载体,即多个基因的集合,其内部表现(即基因型)是某种基因组合,它决定了个体的形状的外部表现,如黑头发的特征是由染色体中控制这一特征的某种基因组合决定的。因此,在一开始需要实现从表现型到基因型的映射即编码工作。由于仿照基因编码的工作很复杂,我们往往进行简化,如二进制编码,初代种群产生之后,按照适者生存和优胜劣汰的原理,逐代(generation)演化产生出越来越好的近似解,在每一代,根据问题域中个体的适应度(fitness)大小选择(selection)个体,并借助于自然遗传学的遗传算子(genetic operators)进行组合交叉(crossover)和变异(mutation),产生出代表新的解集的种群。这个过程将导致种群像自然进化一样的后生代种群比前代更加适应于环境,末代种群中的最优个体经过解码(decoding),可以作为问题近似最优解。

1.1发展概况

起源(20世纪40年代):从生物学的角度进行生物的进化过程模拟、遗传过程等研究工作。§ 产生(20世纪60年代):l 1962年,Fraser提出自然遗传算法。l 1965年,Holland首次提出人工遗传操作的重要性。l 1967年,Bagley首次提出遗传算法这一术语。l 1970年,Cavicchio把遗传算法应用于模式识别中。l 1971年,Hollstien在论文《计算机控制系统中人工遗传自适应方法》中阐述了遗传算法用于数字反馈控制的方法。

1.2算法基本思想

遗传算法的基本思想是从初始种群出发,采用优胜劣汰、适者生存的自然法则选择个体,并通过杂交、变异来产生新一代种群,如此逐代进化,直到满足目标为止。遗传算法所涉及到的基本概念主要有以下几个:
• 种群(Population):种群是指用遗传算法求解问题时,初始给定的多个解的集合。遗传算法的求解过程是从这个子集开始的。
•个体(Individual):个体是指种群中的单个元素,它通常由一个用于描述其基本遗传结构的数据结构来表示。例如,可以用0、1组成的长度为l的串来表示个体。
• 染色体(Chromosome):染色体是指对个体进行编码后所得到的编码串。染色体中的每1位称为基因,染色体上由若干个基因构成的一个有效信息段称为基因组。
• 适应度(Fitness)函数:适应度函数是一种用来对种群中各个个体的环境适应性进行度量的函数。其函数值是遗传算法实现优胜劣汰的主要依据。
• 遗传操作(Genetic Operator):遗传操作是指作用于种群而产生新的种群的操作。标准的遗传操作包括以下3种基本形式:
– 选择(Selection)
– 杂交(Crosssover)
– 变异(Mutation)

2.TSP(旅行商)问题简介

旅行商问题(TravelingSalesmanProblem,TSP)是一个经典的组合优化问题。经典的TSP可以描述为:一个商品推销员要去若干个城市推销商品,该推销员从一个城市出发,需要经过所有城市后,回到出发地。应如何选择行进路线,以使总的行程最短。从图论的角度来看,该问题实质是在一个带权完全无向图中,找一个权值最小的Hamilton回路。由于该问题的可行解是所有顶点的全排列,随着顶点数的增加,会产生组合爆炸,它是一个NP完全问题。由于其在交通运输、电路板线路设计以及物流配送等领域内有着广泛的应用,国内外学者对其进行了大量的研究。早期的研究者使用精确算法求解该问题,常用的方法包括:分枝定界法、线性规划法、动态规划法等。但是,随着问题规模的增大,精确算法将变得无能为力,因此,在后来的研究中,国内外学者重点使用近似算法或启发式算法,主要有遗传算法、模拟退火法、蚁群算法、禁忌搜索算法、贪婪算法和神经网络等。

2.1算法流程图

在这里插入图片描述

3.利用遗传算法解决TSP问题

3.1代码截图

mian.m

%main
clear;
clc;
%%%%%%%%%%%%%%%输入参数%%%%%%%%
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]);
figure(2);
plot_route(pos,R);      %%画出初始种群对应各城市之间的连线
axis([-3 3 -3 3]);
%%初始化种群及其适应函数
fitness=zeros(M,1);
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);
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;
iter=0;
while iter<=ITER
    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
           popm_sel(i,:)=Mutation(popm_sel(i,:));
        end
    end

    %%求适应度函数
    NN=size(popm_sel,1);
    len=zeros(NN,1);
    for i=1:NN
        len(i,1)=myLength(D,popm_sel(i,:));
    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;
    %pause(1);

end
%end of while

figure(3)
plot_route(pos,R);
axis([-3 3 -3 3]);
figure(4)
plot(distance_min);

cross.m

%交叉操作函数  cross.m
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

end

exchange.m

%对调函数 exchange.m

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

fit.m

%适应度函数fit.m,每次迭代都要计算每个染色体在本种群内部的优先级别,类似归一化参数。越大约好!
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

Mutation.m

%变异函数 Mutation.m

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

Mylength.m

%染色体的路程代价函数  mylength.m
function len=myLength(D,p)%p是一个排列
[N,NN]=size(D);
len=D(p(1,N),p(1,1));
for i=1:(N-1)
    len=len+D(p(1,i),p(1,i+1));
end
end

plot_route.m

%连点画图函数 plot_route.m

function plot_route(a,R)
scatter(a(:,1),a(:,2),'rx');
hold on;
plot([a(R(1),1),a(R(length(R)),1)],[a(R(1),2),a(R(length(R)),2)]);
hold on;
for i=2:length(R)
    x0=a(R(i-1),1);
    y0=a(R(i-1),2);
    x1=a(R(i),1);
    y1=a(R(i),2);
    xx=[x0,x1];
    yy=[y0,y1];
    plot(xx,yy);
    hold on;
end

 

end

pos.mat
在这里插入图片描述 在这里插入图片描述

3.2实验结果分析

(1)固定城市序列种群规模对算法的影响

1 迭代次数:2000 种群规模:100 交叉概率:0.8 变异概率:0.05
在这里插入图片描述
2 迭代次数:2000 种群规模:20 交叉概率:0.8 变异概率:0.05
在这里插入图片描述
3 迭代次数:2000 种群规模:50 交叉概率:0.8 变异概率:0.05

在这里插入图片描述
4 迭代次数:2000 种群规模:80 交叉概率:0.8 变异概率:0.05
在这里插入图片描述
说明:当固定城市序列改变种群规模时,根据4组数据得出,种群规模不应太小,可以看出图234并不是最优解,所以种群规模并不是越小越好。四组实验中,不能得出最优说明函数搜索能力不行,但如果种群规模过大的话又会导致算法时间增长,且易陷入局部最优,所以种群规模不应过大且过小,即种群规模最好取50-100间。本实验取种群规模100。

(2)固定城市序列交叉概率对算法的影响

1 迭代次数:2000 种群规模:100 交叉概率:0.8 变异概率:0.05
在这里插入图片描述
2 迭代次数:2000 种群规模:100 交叉概率:0.3 变异概率:0.05
在这里插入图片描述
3 迭代次数:2000 种群规模:100 交叉概率:0.5 变异概率:0.05
在这里插入图片描述
4 迭代次数:2000 种群规模:100 交叉概率:0.9 变异概率:0.05
在这里插入图片描述
说明:四组实验中当变异概率为0.5时具有最优解,其他几组实验都不具有最优解,但收敛速度时最快的。变异概率的选择是影响算法的行为和性能的关键所在,概率过大,新个体产生的速度就越快,遗传模式被破坏的可能性越大,但如果交叉概率过小,会使搜索过程缓慢,以至于停滞不前。经过实验交叉概率取0.3-0.8之间为最优本实验中取交叉概率0.5.

(3)固定城市序列变异概率对算法的影响

1 迭代次数:2000 种群规模:100 交叉概率:0.5 变异概率:0.05
在这里插入图片描述
2 迭代次数:2000 种群规模:100 交叉概率:0.5 变异概率:0.01
在这里插入图片描述
3 迭代次数:2000 种群规模:100 交叉概率:0.5 变异概率:0.09
在这里插入图片描述
4迭代次数:2000 种群规模:100 交叉概率:0.5 变异概率:0.5
在这里插入图片描述
说明:当变异概率过小时,函数收敛变慢。当变异概率过大时,函数变化波动变大,且难以收敛。变异概率取值过小就不易产生新的个体结构,取值过大,那么遗传算法就变成了纯粹的随即搜索算法,所以变异概率和交叉概率都不应过大且过小,本实验中取变异概率为0.05为最优。

(4)固定城市序列迭代次数对算法的影响

1 迭代次数:2000 种群规模:100 交叉概率:0.5 变异概率:0.05
在这里插入图片描述
2 迭代次数:1000 种群规模:100 交叉概率:0.5 变异概率:0.05
在这里插入图片描述
3 迭代次数:500 种群规模:100 交叉概率:0.5 变异概率:0.05
在这里插入图片描述
4 迭代次数:5000 种群规模:100 交叉概率:0.5 变异概率:0.05
在这里插入图片描述
说明:若迭代次数过多,增大程序运行时间,降低算法的运行效率,会陷入局部最优解,只会增加时间开支和资源浪费。若迭代次数过少,迭代次数过小,难以收敛到最优,最短路径曲线多波动。因此,在实现遗传算法的时候应根据实际情况选定合适的迭代次数,不应一味选取较大的值。本文中,取迭代2000次。

4.总结

  • 遗传算法具有良好的全局搜索能力,可以快速地将解空间中的全体解搜索出,而不会陷入局部最优解的快速下降陷阱;并且利用它的内在并行性,可以方便地进行分布式计算,加快求解速度。但是遗传算法的局部搜索能力较差,导致单纯的遗传算法比较费时,在进化后期搜索效率较低。
  • 变异概率及交叉概率是影响遗传算法性能和行为的关键,都是通过产生新个体或个体结构来影响算法的收敛以及收缩过程,当两者过大会导致算法难以收敛。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值