遗传算法求解TSP问题

问题描述

旅行的商人(Travel Salesman)如何规划最短的路线走遍31个地点。

问题分析

将31个地点编号,其顺序作为基因,适应度为(1-归一化的总距离),初始化一个种群,经过若干代选择,交叉,变异,挑选出适应度最大的对应的就是最短距离。

Matlab代码

初始化参数

clear all;      %清除所有变量
close all;      %清图
clc;            %清屏
C=[1304 2312;3639 1315;4177 2244;3712 1399;3488 1535;3326 1556;...
    3238 1229;4196 1044;4312 790;4386 570;3007 1970;2562 1756;...
    2788 1491;2381 1676;1332 695;3715 1678;3918 2179;4061 2370;...
    3780 2212;3676 2578;4029 2838;4263 2931;3429 1908;3507 2376;...
    3394 2643;3439 3201;2935 3240;3140 3550;2545 2357;2778 2826;...
    2370 2975];
N=size(C,1);    %城市数目,基因数目
D=zeros(N);     %任意两个城市距离矩阵
NP=100;         %染色体数目,不是越多越好
G=2000;         %最大遗传代数
Pc=0.1;         %交叉率
f=zeros(NP,N);  %中间变量
F=[];
len=zeros(NP,1);
Fit=zeros(NP,1);

求两点间距

for i=1:N
    for j=1:N
        D(i,j)=((C(i,1)-C(j,1))^2+(C(i,2)-C(j,2))^2)^0.5;
    end
end

随机生成第一代

for i=1:NP
    f(i,:)=randperm(N);
end

计算路径总长度

    for np=1:NP
        len(np,1)=D(f(np,N),f(np,1));
        for n=1:(N-1)
            len(np,1)=len(np,1)+D(f(np,n),f(np,n+1));
        end
    end
    maxlen=max(len);
    minlen=min(len);

更新最短路径

    rr=find(len==minlen);
    fBest=f(rr(1,1),:);

归一化适应度

路径越短,适应度越大

for i=1:length(len)
        Fit(i,1)=(1-((len(i,1)-minlen)/(maxlen-minlen))).^1; 
    end

选择操作

随机选择出一部分数目随机的适应度大的个体,此时数目比初始减少。随机选出其中两个作为父母,交配产生两个新个体,加入到新种群,在同一代中反复如此操作,使种群数目扩增到与初始种群相同。
注意

  • 如果选取适应度最大的两个个体来交配,可能会减少生物多样性,导致早熟。
  • 新种群是由一部分适应度大的父代和一部分交配出来的子代组成的。
    nn=0;
    for np=1:NP
        if Fit(np,1)>=rand
            nn=nn+1;
            F(nn,:)=f(np,:);
        end
    end
    [aa,bb]=size(F);
    while aa<NP
        nnper=randperm(nn);
        A=F(nnper(1),:);
        B=F(nnper(2),:);

randperm()函数用法

P=randperm(N)返回一个包含N个在0到N之间产生的随机元素的向量
例如:randperm(6)可能为[2 4 5 6 1 3]
P=randperm(N,K)返回一个包含K个在0到N之间的随机元素向量
例如:randperm(6,3)可能为[4 2 5]

size()函数用法

x=[1,2,3;4,5,6]是一个2*3的矩阵,则:
d = size(X); %返回矩阵的行数和列数,保存在d中
[m,n] = size(X)%返回矩阵的行数和列数,分别保存在m和n中
m = size(X,dim);%返回矩阵的行数或列数,dim=1返回行数,dim=2返回列数

交叉操作

两个染色体交换一段连续的基因,还要防止交换的基因重复

        W=ceil(N*Pc);
        p=unidrnd(N-W+1);
        for i=1:W
            x=find(A==B(1,p+i-1));
            y=find(B==A(1,p+i-1));
            temp=A(1,p+i-1);
            A(1,p+i-1)=B(1,p+i-1);
            B(1,p+i-1)=temp;
            temp=A(1,x);
            A(1,x)=B(1,y);
            B(1,y)=temp;
        end

unidrnd()函数用法

R = unidrnd(N)
产生从1到N所指定的最大数数之间的离散均匀随机数。其中N可以是一个向量、矩阵、多维数组(当然也可以是一个数,即1乘以1的矩阵),但N中所有元素都必须是正整数。这种调用方式将产生一个和N具有相同尺寸(行、列、维数)的矩阵R。
R = unidrnd(N,m,n)
这里m和n分别指定生成的矩阵R的行数和列数。

取整函数

fix(x):向0取整(也可以理解为向中间取整)
floor(x):向左取整
ceil(x):向右取整

变异操作

染色体自身两个基因对调位置,且相互交叉的一对染色体变异位置不同

        p1=floor(1+N*rand());
        p2=floor(1+N*rand());
        while p1==p2
            p1=floor(1+N*rand());
            p2=floor(1+N*rand());
        end
        tmp=A(1,p1);
        A(1,p1)=A(1,p2);
        A(1,p2)=tmp;
        tmp=B(1,p1);
        B(1,p1)=B(1,p2);
        B(1,p2)=tmp;

遗传循环代码汇总

for gen=1:G
    %%%%%计算路径长度%%%%%
    for np=1:NP
        len(np,1)=D(f(np,N),f(np,1));
        for n=1:(N-1)
            len(np,1)=len(np,1)+D(f(np,n),f(np,n+1));
        end
    end
    maxlen=max(len);
    minlen=min(len);
    %%%%%更新最短路径%%%%%
    rr=find(len==minlen);
    fBest=f(rr(1,1),:);
    %%%%%计算归一化适应度%%%%%
    for i=1:length(len)
        Fit(i,1)=(1-((len(i,1)-minlen)/(maxlen-minlen+0.0001))).^1; 
    end
    %%%%%选择操作%%%%%
    nn=0;
    for np=1:NP
        if Fit(np,1)>=rand
            nn=nn+1;
            F(nn,:)=f(np,:);
        end
    end
    [aa,bb]=size(F);
    while aa<NP
        nnper=randperm(nn);
        A=F(nnper(1),:);
        B=F(nnper(2),:);
        %%%%%交叉操作%%%%
        W=ceil(N*Pc);
        p=unidrnd(N-W+1);
        for i=1:W
            x=find(A==B(1,p+i-1));
            y=find(B==A(1,p+i-1));
            temp=A(1,p+i-1);
            A(1,p+i-1)=B(1,p+i-1);
            B(1,p+i-1)=temp;
            temp=A(1,x);
            A(1,x)=B(1,y);
            B(1,y)=temp;
        end
        %%%%%变异操作%%%%%
        p1=floor(1+N*rand());
        p2=floor(1+N*rand());
        while p1==p2
            p1=floor(1+N*rand());
            p2=floor(1+N*rand());
        end
        tmp=A(1,p1);
        A(1,p1)=A(1,p2);
        A(1,p2)=tmp;
        tmp=B(1,p1);
        B(1,p1)=B(1,p2);
        B(1,p2)=tmp;
        F=[F;A;B];    %把交配出的两个新个体增加到新的种群
        [aa,bb]=size(F); %相当于aa=aa+2
    end
    if aa>NP          %由于随机选出的nn有可能为奇数
        F=F(1:NP,:);  %以此来保证种群数目稳定
    end
    f=F;
    clear F;
    trace(gen)=minlen;
end

画图

figure
for i=1:N-1
    plot([C(fBest(i),1),C(fBest(i+1),1)],[C(fBest(i),2),C(fBest(i+1),2)],'bo-')
    hold on
end
plot([C(fBest(N),1),C(fBest(1),1)],[C(fBest(N),2),C(fBest(1),2)],'bo-')
title(['最优化距离',num2str(minlen)]);
figure
plot(trace)
xlabel('迭代次数')
ylabel('目标函数值')
title('适应度进化曲线')

连接两个散点的方法
plot([x1,x2],[y1,y2])

优化结果

这里写图片描述
这里写图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值