https://www.bilibili.com/video/av22056690/?redirectFrom=h5
这个链接是B站上的一个教学视频,读者可以打开看看,讲得很详细,这是第四章的内容
clear %运用了仿生学中的生物遗传变异,如果感觉结果不是很优,你可以增大迭代次数,这里设了200次
clc
close all
X = [16.47,96.10
16.47,94.44
20.09,92.54
22.39,93.37
25.23,97.24
22.00,96.05
20.47,97.02
17.20,96.29
16.30,97.38
14.05,98.12
16.53,97.38
21.52,95.59
19.41,97.13
20.09,92.55]; %各个城市的坐标位置
NIND = 100; %种群大小
MAXGEN = 200; %最大迭代次数
Pc = 0.9; %交叉概率,相当于基因遗传的时候染色体交叉
Pm = 0.05; %染色体变异
GGAP = 0.9; %这个是代沟,通过遗传方式得到的子代数为父代数*GGAP
D = Distance(X); %通过这个函数可以计算i,j两点之间的距离
N = size(D,1); %计算有多少个坐标点
%%初始化种群
Chrom = InitPop(NIND,N); %Chrome代表的种群
%%在二维图上画出所有的坐标点
%figure
%plot(X(;,1),X(;,2),'o');
%%画出随机解得路线图
DrawPath(Chrom(1,:),X)
pause(0.0001)
%输出随机解的路线和总距离
disp('初始种群中的一个随机值')
OutputPath(Chrom(1,:));%其中一个个体
Rlength = PathLength(D,Chrom(1,:));
disp(['总距离;',num2str(Rlength)]);
disp('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
%优化
gen = 0;
figure;
hold on;
box on;
xlim([0,MAXGEN])
title('优化过程')
xlabel('代数')
ylabel('最优值')
ObjV = PathLength(D,Chrom); %计算当前路线长度,即上面随机产生的那些个体路径
preObjV = min(ObjV);%找出当前个体重最小的那个
while gen
function D = Distance(a)
%%计算两两城市之间的距离
%输入 a 各城市的位置坐标
%输出 D 两两城市之间的距离
row = size(a,1);
D = zeros(row,row);
for i = 1:row
for j = i+1:row
D(i,j) = ((a(i,1) - a(j,1))^2 + (a(i,2)-a(j,2))^2)^0.5;
D(j,i) = D(i,j);
end
end
function Chrom = InitPop(NIND,N)%初始化种群,
%输入:
%NIND:种群大小
%N:个体染色体长度(城市个数)
%输出:
%初始种群
Chrom = zeros(NIND,N); %用于存储种群
for i = 1:NIND
Chrom(i,:) = randperm(N);%随机生成初始种群,randperm函数的用法是返回一行1~N的整数,这N个数是不同的
end
function DrawPath(Chrom,X)
%%画路线图函数
%输入:
%Chrom 待画路线
%X 个城市的坐标位置
R = [Chrom(1,:) Chrom(1,1)]; %一个随机解(个体),一共有14个城市,但是这里R有15个值,因为后面又补了一个Chrom(1,1),“是为了让路径最后再回到起点”,这是R初始值[6,3,11,7,14,8,5,1,2,4,13,9,10,12,6],可以发现前14个值因为randperm函数都是不一样的
figure;
hold on
plot(X(:,1),X(:,2),'o','color',[0.5,0.5,0.5])%X(:,1),X(:,2)分别代表的X轴坐标和Y轴坐标,[0.5,0.5,0.5]表示对应的坐标用圆圈表示
%plot(X(:,1),X(:,2),'o','color',[1,1,1])%X(:,1),X(:,2)分别代表的X轴坐标和Y轴坐标,
plot(X(Chrom(1,1),1),X(Chrom(1,1),2),'rv','MarkerSize',20)%标记起点
for i = 1:size(X:1)
text(X(i,1)+0.05,X(i,2)+0.05,num2str(i),'color',[1,0,0]);
end %感觉这个for循环没什么用,我去掉了,对结果也没什么影响,无非即使第一张图上标了个1,可能是我太菜了吧
A = X(R,:); %A是将之前的坐标顺序用R打乱后重新存入A中
row = size(A,1); %row为坐标数+1
for i = 2:row
[arrowx,arrowy] = dsxy2figxy(gca,A(i-1:i,1),A(i-1:i,2)); %dsxy2figxy坐标转换函数,记录两个点
annotation('textarrow',arrowx,arrowy,'HeadWidth',8,'color',[0,0,1]);%将这两个点连接起来
end
hold off
xlabel('横坐标')
ylabel('纵坐标')
title('轨迹图')
box on
function p=OutputPath(R)
%%输出路线函数
%输入 R 路线
R = [R,R(1)];
N = length(R);
p = num2str(R(1));
for i = 2:N
p = [p,'->',num2str(R(i))];
end
disp(p)
function len = PathLength(D,Chrom)
%%计算所有个体的路线长度
%输入
%D 两两城市之间的距离
%Chrom 个体的轨迹
[row,col] = size(D);
NIND = size(Chrom,1);
len = zeros(NIND,1);
for i = 1:NIND
p = [Chrom(i,:) Chrom(i,1)];
i1 = p(1:end-1);
i2 = p(2:end);
len(i,1) = sum(D((i1-1)*col+i2));
end
function SelCh = Select(Chrom,FitnV,GGAP)%%选择操作
%输入:
%Chrom 种群
%FitnV 适应度值
%GGAP 选择概率
%输出:
%SelCh 被选择的个体
NIND = size(Chrom,1);
NSel = max(floor(NIND * GGAP+.5),2);
ChrIx = Sus(FitnV,NSel);
SelCh = Chrom(ChrIx,:);
function SelCh = Recombin(SelCh,Pc)
%交叉操作
%输入:
%SelCh 被选择的个体
%Pc 交叉概率
%输出:
%SelCh 交叉后的个体
NSel = size(SelCh,1);
for i = 1:2:NSel - mod(NSel,2)
if Pc>=rand %交叉概率PC
[SelCh(i,:),SelCh(i+1,:)] = intercross(SelCh(i,:),SelCh(i+1,:));
end
end
function SelCh = Mutate(SelCh,Pm)
%变异操作
%输入:
%SelCh 被选择的个体
%Pm 变异概率
%输出:
%SelCh 变异后的个体
[NSel,L] = size(SelCh);
for i = 1:NSel
if Pm >= rand
R = randperm(L);
SelCh(i,R(1:2)) = SelCh(i,R(2:-1:1));
end
end
function SelCh = Reverse(SelCh,D)
%%进化逆转函数
%输入:
%SelCh 被选择的个体
%D 各城市的距离矩阵
%输出:
%SelCh 进化逆转后的个体
[row,col] = size(SelCh);
ObjV = PathLength(D,SelCh);
SelCh1 = SelCh;
for i = 1:row
r1 = randsrc(1,1,[1:col]);
r2 = randsrc(1,1,[1:col]);
mininverse = min([r1 r2]);
maxinverse = max([r1 r2]);
SelCh1(i,mininverse:maxinverse) = SelCh1(i,maxinverse:-1:mininverse);
end
ObjV1 = PathLength(D,SelCh1);%计算路线长度
index = ObjV1
function Chrom = Reins(Chrom,SelCh,ObjV)
%%重插入子代的种群
%输入:
%Chrom 父代的种群
%SelCh 子代的种群
%ObjV 父代适应度
%输出:
%Chrom 组合父代与子代后得到的新种群
NIND = size(Chrom,1);
NSel = size(SelCh,1);
[TobjV,index] = sort(ObjV);
Chrom = [Chrom(index(1:NIND-NSel),:);SelCh];