遗传算法解决旅行商问题

旅行商问题简介

给定一系列城市和每对城市之间的距离,求解访问每一座城市一次并回到起始城市的最短回路。它是组合优化中的一个NP难问题,在运筹学和理论计算机科学中非常重要。

遗传算法

遗传算法已经在之前的博客详细介绍过:遗传算法 因此这边不再多加赘述
由于上次解决的是使用遗传算法解决函数优化问题,交叉操作只要交换0和1就行,而在这次问题中,随机选择两个个体,再随机选择一段基因进行交换,以完成交叉操作,很容易在城市序列中包含重复的城市。
比如一下两个个体之间的交叉
A: 9 1 2 3 5 4 7 6 8 10
B: 10 5 6 4 3 8 7 2 1 9
得到
A: 9 1 2 4 3 8 7 6 8 10
B: 10 5 6 3 5 4 7 2 1 9
可见,两者交换基因段为3 5 4 7和4 3 8 7,保持此段不变,对于A,第一个冲突基因为8,将交换段外冲突基因替换为B中相应位置的基因即5,多次执行直到没有冲突得到基因:
A:9 1 2 4 3 8 7 6 5 10
B:10 8 6 3 5 4 7 2 1 9

而变异操作则是将同一城市序列的两个城市进行交换

代码展示

变异函数 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

对调函数 exchange.m

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

染色体的路程代价函数 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

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

适应度函数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

交叉操作函数 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

main.m

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);

测试数据

N=25; %%城市的个数
M=100; %%种群的个数
ITER=2000; %%迭代次数

m=2; %%适应值归一化淘汰加速指数
Pc=0.8; %%交叉概率
Pmutation=0.05; %%变异概率
%%生成城市的坐标
pos=[
0.537667139546100 1.03469300991786
1.83388501459509 0.726885133383238
-2.25884686100365 -0.303440924786016
0.862173320368121 0.293871467096658
0.318765239858981 -0.787282803758638
-1.30768829630527 0.888395631757642
-0.433592022305684 -1.14707010696915
0.342624466538650 -1.06887045816803
3.57839693972576 -0.809498694424876
2.76943702988488 -2.94428416199490
-1.34988694015652 1.43838029281510
3.03492346633185 0.325190539456198
0.725404224946106 -0.754928319169703
-0.0630548731896562 1.37029854009523
0.714742903826096 -1.71151641885370
-0.204966058299775 -0.102242446085491
-0.124144348216312 -0.241447041607358
1.48969760778547 0.319206739165502
1.40903448980048 0.312858596637428
1.41719241342961 -0.864879917324457
0.671497133608081 -0.0300512961962686
-1.20748692268504 -0.164879019209038
0.717238651328839 0.627707287528727
1.63023528916473 1.09326566903948
0.488893770311789 1.10927329761440 ]
;

运行结果

在这里插入图片描述左上图为城市的坐标,一共有25个城市
右上图为初始种群的路线
左下图为最终路线
右下图为迭代次数
在这里插入图片描述可以看出迭代到370次时,已找到最短路径,最短路径的值为26.93760
最短路径序列为
14 11 6 16 23 12 9 10 17 22 3 7 15 20 13 8 5 21 4 19 18 2 24 1 25

不同参数下的运行结果

1.交叉概率为改变,变异概率为0.05,种群个数为100

交叉概率迭代次数最短距离
0.2196824.75382
0.448224.14478
0.682123.58496
0.830426.08873
1168223.04163

在其他参数不变的情况下,随着交叉概率的增加,迭代次数以先减后增再减再增的曲线变化(去掉特殊情况),这说明交叉概率有明显的优势区间,本次实验大概在[0.4,0.8]间取得最优效果。

在这里插入图片描述
在交叉概率为0.2时,到达1968次时,曲线发生了变化,后来又变化为之前一样的情况,特殊情况特殊记录

2.交叉概率为0.8,变异概率为改变,种群个数为100

变异概率迭代次数最短距离
0.01137525.02534
0.0332124.80349
0.0550123.28053
0.0730722.35342
0.09136123.14003

%在其他参数不变的情况下,随着变异概率的增加,迭代次数以一种w曲线的变化,在[0.03,0.05]及[0.05,0.07]的迭代次数最少,效果最好。
3.交叉概率为0.8,变异概率为0.05,种群个数改变

种群个数迭代次数最短距离
100106124.18065
20025124.40206
30012721.56703
40039824.40347
50020823.05599

明显可以看出,其他参数不变的前提下,随着种群数量的增多,迭代次数先增加后减少。到达[200,300]的时候,效果最好。

实验结论

本次实验与之前的蚁群算法做对比,明显运行速度快于蚁群算法。遗传算法具有良好的全局搜索能力,可以快速地将解空间中的全体解搜索出,而不会陷入局部最优解的快速下降陷阱;并且利用它的内在并行性,可以方便地进行分布式计算,加快求解速度。但是遗传算法的局部搜索能力较差,导致单纯的遗传算法比较费时,在进化后期搜索效率较低。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值