数学建模之遗传算法(含matlab代码)

前言

本文以面向数学建模的同学为主,不适合想要深入研究此算法的同学,不涉及过多专业知识,尽量让大家在短时间内快速了解这个算法的大体内容,并能用matlab编程加以实现,有时间的话可以自己把代码敲一遍,代码关键部分都有注释,对自己的matlab编程能力还是有一定帮助的,没有时间的话,我也在文中介绍了哪些是可以直接套用的,哪些是需要依据具体问题修改的,有任何疑问,欢迎留言

遗传算法

简介

遗传算法(Genetic Algorithm,GA)该算法是根据大自然中生物体进化规律而设计提出的。是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。

算法主体

概括

整个算法就是,我们用一种编码格式表示我们种群,该种群就是直接和我们要求解的问题相关的,然后我们随机产生50个初始种群(50是可以变的,不过一般可以直接取50,该种群也可以用一定的算法进行择优选择),这些种群构成了我们的初始种群群体,然后我们对这些初始种群群体进行操作不断迭代出更优的新解,这些操作包括交叉、变异、遗传等,然后经过一定的迭代次数之后,就会的到我们最终的解,也是50个种群,我们从50个种群中选出最优的种群,即我们问题的答案

编码格式

一般在选择编码格式时,要结合具体问题具体分析,这个是需要自己设计的,常用的编码格式有二进制编码、十进制编码等,可以往下翻翻看看本文要解决的问题,本文程序中采用的是十进制编码,通过十进制编码,我们可以这样表示一个种群,1->4-79->5->…->6->10->102,1和102表示我们的起点和终点,它们中间包含2~101的一个随机排列,表示我们中间要经过的100个点,通过这个一维矩阵我们可以很好的表示我们的行走路线,通过距离矩阵我们也能很轻易的求出每段路程进而求出总路程,能很好的表示问题的解,这是我们选择编码格式最重要的一点

适应度函数

这个就是我们比较两个解,哪个解较优的一种判别方法,然后我们将保留较优的那个解,这个也是自己依据问题自己设计的,本文程序中较为简单,它的目标函数就是比较二者整个行驶路线的总距离,较短的那个就是较优的

交叉操作

这个是我们选定了初始种群群体以后,产生新种群的一种方式,随机选择种群两两进行交叉,这个也是自己设计的,本文程序中是这样进行交叉操作的,随机选择好两个种群之后,随机产生一个下标,把这两个种群中,该下标到该种群末尾整个进行互换形成交叉操作

变异操作

变异操作是我们为了防止局部最优解而进行的操作,在较小概率内,随机选择种群进行变异操作,本文程序选取的概率是10%,进行变异操作的原理是在一个种群内随机形成三个下标,三个下标,夹杂着两个区间段,该变异操作就是直接把两个区间段进行互换

各个变量设置

种群规模: 20~200都可,一般直接取50
交叉系数: 系数较大会破坏整个种群优良的结构,较小则产生新个体的速度较慢。一般设置在0.4~0.99,本文采用的是随机概率
变异概率: 系数较小则可能产生局部最优,系数较大则会随机性过强,一般取0.0005~0.01,本文以10%概率选出种群,然后在种群内部随机选出片段进行变异
终止迭代次数: 100以上都行,具体看整个问题规模,迭代次数过大唯一的缺点就是程序运行时间长,没有这个顾虑的话可以设大点,本文取得是100

算法总结

该算法最大的难点就是编码格式的设计和适应度函数的选取,编码格式设计好了,整个交叉操作和变异操作都迎刃而解,编码格式设计的要能表示整个解,适应度函数要能比较两个解的优劣,在数学建模中,可以写到论文中去的两个图片,一个是最终的运行结果图,一个是整个迭代次数内整个种群的优化过程,该算法准确来说是求出较优解,每次运行的结果可能不同

问题和代码

问题

一个飞机从(70,40)出发依次经过100个点,然后返回起点,求最短路线(给出的数据坐标是经纬度)

数据

53.7121 15.3046 51.1758 0.0322 46.3253 28.2753 30.3313 6.9348
56.5432 21.4188 10.8198 16.2529 22.7891 23.1045 10.1584 12.4819
20.1050 15.4562 1.9451 0.2057 26.4951 22.1221 31.4847 8.9640
26.2418 18.1760 44.0356 13.5401 28.9836 25.9879 38.4722 20.1731
28.2694 29.0011 32.1910 5.8699 36.4863 29.7284 0.9718 28.1477
8.9586 24.6635 16.5618 23.6143 10.5597 15.1178 50.211 10.2944
8.1519 9.5325 22.1075 18.5569 0.1215 18.8726 48.2077 16.8889
31.9499 17.6309 0.7732 0.4656 47.4134 23.7783 41.8671 3.5667
43.5474 3.9061 53.3524 26.7256 30.8165 13.4595 27.7133 5.0706
23.9222 7.6306 51.9612 22.8511 12.7938 15.7307 4.9568 8.3669
21.5051 24.0909 15.2548 27.2111 6.2070 5.1442 49.2430 16.7044
17.1168 20.0354 34.1688 22.7571 9.4402 3.9200 11.5812 14.5677
52.1181 0.4088 9.5559 11.4219 24.4509 6.5634 26.7213 28.5667
37.5848 16.8474 35.6619 9.9333 24.4654 3.1644 0.7775 6.9576
14.4703 13.6368 19.8660 15.1224 3.1616 4.2428 18.5245 14.3598
58.6849 27.1485 39.5168 16.9371 56.5089 13.7090 52.5211 15.7957
38.4300 8.4648 51.8181 23.0159 8.9983 23.6440 50.1156 23.7816
13.7909 1.9510 34.0574 23.3960 23.0624 8.4319 19.9857 5.7902
40.8801 14.2978 58.8289 14.5229 18.6635 6.7436 52.8423 27.2880
39.9494 29.5114 47.5099 24.0664 10.1121 27.2662 28.7812 27.6659
8.0831 27.6705 9.1556 14.1304 53.7989 0.2199 33.6490 0.3980
1.3496 16.8359 49.9816 6.0828 19.3635 17.6622 36.9545 23.0265
15.7320 19.5697 11.5118 17.3884 44.0398 16.2635 39.7139 28.4203
6.9909 23.1804 38.3392 19.9950 24.6543 19.6057 36.9980 24.3992
4.1591 3.1853 40.1400 20.3030 23.9876 9.4040 41.1084 27.7149
第一列和第二列表示1到25个点的坐标,第三列和第四列表示26到50个点的坐标,以此类推,可直接复制到txt文档,文档命名为sj.txt,然后运行程序观察结果

matlab程序

sj0=load('sj.txt'); % 载入数据
x=sj0(:,(1:2:8));
x=x(:);
y=sj0(:,(2:2:8));
y=y(:);
sj=[x,y];
d1=[70,40];
sj=[d1;sj;d1];
sj=sj*pi/180; % 将角度转化为弧度
d=zeros(102);
for i=1:101
    for j=i+1:102
        d(i,j)=6370*acos(cos(sj(i,1)-sj(j,1))*cos(sj(i,2))*cos(sj(j,2))+sin(sj(i,2))*sin(sj(j,2)));%求任意两点之间距离
    end
end
d = d + d';
w = 50; % 种群数
g = 100; % 进化代数
rand('state', sum(clock));
% 以下通过改良圈算法确定一个初始解
% 最终会选出50行,每行都是随机选出的基数,然后进行换序优化,得到该基数下的较优解
for k = 1 : w
    c = randperm(100);
    c1 = [1, c + 1, 102];
    for t = 1 : 102
        flag = 0;
        for m = 1 : 100
            for n = m + 2 : 101
                if d(c1(m), c1(n)) + d(c1(m + 1), c1(n + 1)) < d(c1(m), c1(m + 1)) + d(c1(n), c1(n+1))
                    c1(m + 1 : n) = c1(n: -1 : m + 1); %逆序比顺序小,则用逆序
                    flag = 1;
                end
            end
        end
        if flag == 0
            J(k, c1) = 1 : 102; %把c1赋值给J当做第k行
            break
        end
    end
end
J(:, 1) = 0; %保证第一列最小,和ind1呼应
J = J / 102;
D=zeros(1,g);
% 以下是遗传算法操作
for k = 1 : g
    A = J;
    c = randperm(w); % 产生交叉染色对
    for i = 1 : 2 : w %50个种群中,随机选出两个进行交配
        F = 2 + floor(100 * rand(1)); % 随机选出需要交叉的片段
        
        % c(i)和c(i+1)在(F:102)段互换
        temp = A(c(i), (F : 102));
        A(c(i), (F : 102)) = A(c(i + 1), (F : 102));
        A(c(i + 1), F : 102) = temp;
    end
    by = [];
    while isempty(by) % 产生变异操作初始染色体
        by = find(rand(1, w) < 0.1); %产生w个0到1之间的数,并把小于0.1的下标保存在by中,得到需要变异个体下标
    end
    B=A(by, :); %取出需要变异种群
    for j = 1 : length(by)
        bw = sort(2 + floor(100 * rand(1, 3)));
        B(j, :) = B(j, [1 : bw(1) - 1, bw(2) + 1 : bw(3), bw(1) : bw(2), bw(3) + 1 : 102]);
        % B不变的正常顺序B(j, [1 : bw(1) - 1, bw(1) : bw(2), bw(2) + 1 : bw(3),
        % bw(3) + 1 : 102]),然后其实是把中间两部分进行了对调,形成变异
    end
    G = [J; A; B]; % 原始种群、交配交叉种群、变异种群三合一
    [SG, ind1] = sort(G, 2); % 按行升序,保留索引,SG(ind1)=G
    num = size(G, 1); % 返回矩阵行数
    long = zeros(1, num); % long矩阵保存G中所有种群的总长度
    for j = 1 : num
        for i = 1 : 101
            long(j) = long(j) + d(ind1(j, i), ind1(j, i + 1)); %求出总长度
        end
    end
    [slong, ind2] = sort(long); % 对路径长度排序
    J = G(ind2(1 : w), :); % 选取前 w 个较短路径的染色体(选择最优质的w个种群,重新进行循环)
    D(k)=sum(slong)/size(slong,2);%保存每次的平均值
end
path = ind1(ind2(1), :), % 解的路径
flong = slong(1), % 解的路径长度
xx = sj(path, 1);
yy = sj(path, 2);
plot(xx, yy, '-o') % 绘制路径
xlabel('经度(弧度制)');
ylabel('纬度(弧度制)');
title('路线图');
hold on;
text(sj(1,1),sj(1,2),'起点','color','r');
figure(2);
x1=1:100;
y1=D;
plot(x1,y1);
xlabel('迭代次数');
ylabel('最优值变化');
title('变化图');

结果展示

一个路线图和一个迭代次数平均值变化图
路线图
变化图

结语

本文部分内容参考这篇博客:https://blog.csdn.net/qq_34554039/article/details/90521834
感谢某位同学提供的图片

猜你喜欢

转载自blog.csdn.net/jiuzhongxian_/article/details/107713754