一、原文链接
简单路径优化问题
网络拓扑:
二、程序思路
以链接为例,我先简单介绍编程思路(序号对应程序的编号),请各位大佬斧正。
将上图节点一次编上序号a-1,b-2,c-3…
①主函数包含了参数函数、初始化函数和迭代函数,最后显示迭代结束后的最短路径及其长度;
②参数函数包含了染色体数、维度、迭代数及变异算子;(注:在下面的程序中,我没有使用到交叉算子)
⑩邻接矩阵函数定义了两个矩阵:邻接矩阵a和路径长度矩阵c,分别用于表示节点的相邻情况及相邻矩阵的路径长度;
③初始化函数用于随机化染色体,我用了基于优先级的染色体编码方式(浮点数编码),根据优先级从第一个节点开始,选择与其相邻的高优先级节点,再以此节点开始,选择预期相邻的下一个高优先级节点,…,一直到选择最后一个节点11结束;然后进行解码,解出路径,计算路径长度;
④编码函数描述了将基于优先级选择节点的染色体解码为路径;具体为将与上一个节点不相邻或序号与上一个节点序号相差小于-3的节点的优先级置零,然后选择优先级最高的那个节点,将其加入路径中,知道最后一个节点11加入到路径中;
⑤适应度函数根据路径长度矩阵即路径数组计算此路径的长度;
⑥迭代函数包含了选择、交叉和变异函数,还有最后的解码计算适应度;
⑦选择函数采用最经典的轮盘赌选择,不过这里需要注意的是,一般适应度大的染色体占所有染色体适应度之和较高,选中的几率也较大,但是路径选择问题是选择较短的路径,因此我将适应度值取了倒数,每次再取两个随机小数,根据小数选择两个染色体,再从中选择适应度高的那个染色体;
⑧交叉函数产生染色体的子代,其中所有子代都是有交叉产生的,但是如果交叉后的子代路径交叉,那么丢弃子代,保留父代;具体操作是随机选择两个父代,随机选择两个交叉点,交叉点间的基因呼唤产生子代;若两个交叉点相同,那么在该交叉点的数值间取两个随机数分别代替父代的两个交叉点的值;(注:在其他前辈的描述中,我经常看到交叉算子这个参数,但是我在本文中并没有用到,暂时也不明白其用途;不过我在使用遗传算法的过程中,发现如果交叉算子采用与变异相同的作用,那么意味着到最后一次迭代仍然会有交叉的操作,尽管到后期适应度值变好,交叉可能并没有改变什么,但是我在后面的使用中采用了同粒子群算法中惯性因子w线性迭代的运算,前期交叉算子较大,随着迭代次数增加,交叉算子减少,最后不交叉,但是好像与遗传算法的思想(每代都有交叉相违背))
⑨变异函数中,当一个随机小数小于变异算子Pm,则选择染色体的一个随机变异点进行变异操作;若产生较好的适应度则保留代替,否则丢弃;
三、程序
①主函数main
clear;
clc;
close all;
[N,D,Iter,Pm] = constant();
GA = zeros(N,D+1);
[Path,GA] = initialization(N,D,GA);
[GA,Path] = iteration(Iter,GA,Path,N,D,Pm);
[mincost,row] = min(Path(:,D+1));
[~,col] = max(Path(row,1:D));
disp(['最短路径:',num2str(Path(row,1:col)),',路径长度:',num2str(mincost)]);
②参数函数constant
function [N,D,Iter,Pm] = constant()
N = 40;
D = 11;
Iter = 200;
Pm = 0.1;%变异算子
③初始化函数initialization
function [Path,GA] = initialization(N,D,GA)
[a,c] = adjacency(D);
Path = zeros(N,D+1);
Path(:,1) = 1;
for i = 1:N
GA(i,2:D) = rand(1,10);
Path(i,1:D) = pathencode(GA(i,1:D),D,a);
Path(i,D+1) = fitness(Path(i,1:D),c);
GA(i,D+1) = Path(i,D+1);
end
④编码函数pathencode
function path = pathencode(x,D,a)
y = 1;
num = 1;
p = x;
path = zeros(1,D);
path(1) = 1;
while(y~=D)
p1 = p;
for j = 2:D
if (a(y,j)~=1)||((j-y)<=-3)
p(j) = 0;
end
end
[~,y] = max(p);
num = num + 1;
path(1,num) = y;
p1(y) = 0;
p = p1;
end
⑤适应度函数fitness
function y = fitness(x,c)
y = 0;
[~,K] = max(x);
for k = 2:K
y = y + c(x(k),x(k-1));
end
⑥迭代函数iteration
function [GA,Path] = iteration(Iter,GA,Path,N,D,Pm)
[a,c] = adjacency(D);
for iter = 1:Iter
GA = select(N,D,GA);
[GA,Path] = crossover(N,D,GA,Path);
GA = mutation(N,D,Pm,GA,Path);
for i = 1:N
Path(i,1:D) = pathencode(GA(i,1:D),D,a);
Path(i,D+1) = fitness(Path(i,1:D),c);
GA(i,D+1) = Path(i,D+1);
end
end
⑦选择函数select
function x = select(N,D,GA)
%轮盘赌
x = GA;
c = zeros(N,1);
[a,b] = sort(x(:,D+1),'descend');
a = 1./a;
s = sum(a(:,1));
for i = 1:N
c(i,1) = sum(a(1:i),1);
c(i,1) = c(i,1)/s;
end
for i = 1:N
d1 = rand;
num1 = min(find(c>d1));
d2 = rand;
num2 = min(find(c>d2));
if a(num1)<a(num2)
x(i,:) = GA(b(num2),:);
else
x(i,:) = GA(b(num1),:);
end
end
⑧交叉函数crossover
function [x,Path] = crossover(N,D,GA,Path)
%顺序交叉
[a,c] = adjacency(D);
x = GA;
[~,colmax] = min(x(:,D+1));
for i = 1:N
x1 = 0;
x2 = 0;
while x1 == x2||x1 == colmax||x2 == colmax %避免选取的两个父代是相同的及保留最好的染色体不变化
x1 = randi([1,N]);
x2 = randi([1,N]);
end
point1 = 0;
point2 = 0;
while (point1 == 0)||(point2 == 0) %避免选取的两个交叉点是相同的
point = randi([1,D],1,2);
point1 = min(point);
point2 = max(point);
end
if point1 == point2
t = min(x(x1,point1),x(x2,point1)) + rand(1,2).*(max(x(x1,point1),x(x2,point1)) - min(x(x1,point1),x(x2,point1)));
x(x1,point1) = min(t);
x(x2,point1) = max(t);
else
x(x1,point1:point2) = GA(x2,point1:point2);
x(x2,point1:point2) = GA(x1,point1:point2);
end
Path(x1,1:D) = pathencode(x(x1,1:D),D,a);
Path(x1,D+1) = fitness(Path(i,1:D),c);
if Path(x1,D+1)>GA(x1,D+1)
x(x1,:) = GA(x1,:);
end
Path(x2,1:D) = pathencode(x(x2,1:D),D,a);
Path(x2,D+1) = fitness(Path(i,1:D),c);
if Path(x2,D+1)>GA(x2,D+1)
x(x2,:) = GA(x2,:);
end
end
⑨变异函数mutation
function x = mutation(N,D,Pm,GA,Path)
[a,c] = adjacency(D);
x = GA;
for i = 1:N
p = rand;
if p <= Pm
point = randi([2,D]);
r = rand;
x(i,point) = abs(x(i,point) - r);
Path(i,1:D) = pathencode(x(i,1:D),D,a);
Path(i,D+1) = fitness(Path(i,1:D),c);
if Path(i,D+1)>GA(i,D+1)
x(i,:) = GA(i,:);
end
end
end
⑩邻接矩阵
function [a,c] = adjacency(D)
a = zeros(D,D);
c = a;
a(1,2) = 1;a(1,3) = 1;a(1,4) = 1;
c(1,2) = 2;c(1,3) = 8;c(1,4) = 1;
a(2,3) = 1;a(2,5) = 1;
c(2,3) = 6;c(2,5) = 1;
a(3,4) = 1;a(3,6) = 1;
c(3,4) = 7;c(3,6) = 1;
a(4,7) = 1;
c(4,7) = 9;
a(5,6) = 1;a(5,8) = 1;
c(5,6) = 3;c(5,8) = 2;
a(6,7) = 1;a(6,9) = 1;
c(6,7) = 4;c(6,9) = 6;
a(7,10) = 1;
c(7,10) = 1;
a(8,9) = 1;a(8,11) = 1;
c(8,9) = 7;c(8,11) = 9;
a(9,10) = 1;a(9,11) = 1;
c(9,10) = 1;c(9,11) = 2;
a(10,11) = 1;
c(10,11) = 4;
a = a + a';
c = c + c';
结果:
注:最短路径不止这一种,但是最短路径长度是14。