问题定义:巡回旅行商问题
给定一组n个城市和俩俩之间的直达距离,寻找一条闭合的旅程,使得每个城市刚好经过一次且总的旅行距离最短。
TSP问题也称为货郎担问题,是一个古老的问题。最早可以追溯到1759年Euler提出的骑士旅行的问题。1948年,由美国兰德公司推动,TSP成为近代组合优化领域的典型难题。
TSP是一个具有广泛的应用背景和重要理论价值的组合优化问题。 近年来,有很多解决该问题的较为有效的算法不断被推出,例如Hopfield神经网络方法,模拟退火方法以及遗传算法方法等。
TSP搜索空间随着城市数n的增加而增大,所有的旅程路线组合数为(n-1)!/2。在如此庞大的搜索空间中寻求最优解,对于常规方法和现有的计算工具而言,存在着诸多计算困难。借助遗传算法的搜索能力解决TSP问题,是很自然的想法。
基本遗传算法可定义为一个8元组:
(SGA)=(C,E,P0,M,Φ,Г,Ψ,Τ)
C ——个体的编码方法,SGA使用固定长度二进制符号串编码方法;
E ——个体的适应度评价函数;
P0——初始群体;
M ——群体大小,一般取20—100;
Ф——选择算子,SGA使用比例算子;
Г——交叉算子,SGA使用单点交叉算子;
Ψ——变异算子,SGA使用基本位变异算子;
Т——算法终止条件,一般终止进化代数为100—500;
问题的表示
对于一个实际的待优化问题,首先需要将其表示为适合于遗传算法操作的形式。用遗传算法解决TSP,一个旅程很自然的表示为n个城市的排列,但基于二进制编码的交叉和变异操作不能适用。
路径表示是表示旅程对应的基因编码的最自然,最简单的表示方法。它在编码,解码,存储过程中相对容易理解和实现。例如:旅程(5-1-7-8-9-4-6-2-3)可以直接表示为(5 1 7 8 9 4 6 2 3)
产生初始种群
一是完全随机产生,它适合于对问题的解无任何先验知识的情况。随机性较强,因而也较公正
二是某些先验知识可转变为必须满足的一组要求,然后在满足这些要求的解中在随机地选取样本。这样选择初始种群可使遗传算法更快的达到最优解。种群有一定的目标性和代表性,但取例不如完全随机的广泛,而且先验知识是否可靠也是一个问题
适应度函数
遗传算法在进化搜索中基本不利用外部信息,仅以适应度函数为依据,利用种群中每个个体的适应度值来进行搜索。TSP的目标是路径总长度为最短,路径总长度的倒数就可以为TSP的适应度函数:

选择
一般地说,选择将使适应度较大(优良)个体有较大的存在机会,而适应度较小(低劣)的个体继续存在的机会也较小。简单遗传算法采用赌轮选择机制,令Σfi表示群体的适应度值之总和,fi表示种群中第i个染色体的适应度值,它产生后代的能力正好为其适应度值所占份额fi/Σfi。
交叉
基于路径表示的编码方法,要求一个个体的染色体编码中不允许有重复的基因码,也就是说要满足任意一个城市必须而且只能访问一次的约束。基本遗传算法的交叉操作生成的个体一般不能满足这一约束条件。
部分匹配交叉操作要求随机选取两个交叉点,以便确定一个匹配段,根据两个父个体中两个交叉点之间的中间段给出的映射关系生成两个子个体。

变异
遗传算法解决TSP 问题基于二进值编码的变异操作不能适用,不能够由简单的变量的翻转来实现
在TSP问题中个体的编码是一批城市的序列,随机的在这个序列抽取两个城市,然后交换他们的位置。这样就实现了个体编码的变异,算法如下:
产生两个0到1之间的随机实数;
将这两个随机实数转化为0到n(城市数)-1之间的随机整数;
将这两个随机整数指代的城市进行交换;
流程图

代码
完整代码参考我的网站:http://www.omegaxyz.com/2019/01/21/matlab-tsp-all/
主函数代码:
clear; clc; tStart = tic; % 算法计时器 %%%%%%%%%%%%自定义参数%%%%%%%%%%%%% [cityNum,cities] = Read('dsj1000.tsp'); cities = cities'; %cityNum = 100; maxGEN = 1000; popSize = 100; % 遗传算法种群大小 crossoverProbabilty = 0.9; %交叉概率 mutationProbabilty = 0.1; %变异概率 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gbest = Inf; % 随机生成城市位置 %cities = rand(2,cityNum) * 100;%100是最远距离 % 计算上述生成的城市距离 distances = calculateDistance(cities); % 生成种群,每个个体代表一个路径 pop = zeros(popSize, cityNum); for i=1:popSize pop(i,:) = randperm(cityNum); end offspring = zeros(popSize,cityNum); %保存每代的最小路劲便于画图 minPathes = zeros(maxGEN,1); % GA算法 for gen=1:maxGEN % 计算适应度的值,即路径总距离 [fval, sumDistance, minPath, maxPath] = fitness(distances, pop); % 轮盘赌选择 tournamentSize=4; %设置大小 for k=1:popSize % 选择父代进行交叉 tourPopDistances=zeros( tournamentSize,1); for i=1:tournamentSize randomRow = randi(popSize); tourPopDistances(i,1) = sumDistance(randomRow,1); end % 选择最好的,即距离最小的 parent1 = min(tourPopDistances); [parent1X,parent1Y] = find(sumDistance==parent1,1, 'first'); parent1Path = pop(parent1X(1,1),:); for i=1:tournamentSize randomRow = randi(popSize); tourPopDistances(i,1) = sumDistance(randomRow,1); end parent2 = min(tourPopDistances); [parent2X,parent2Y] = find(sumDistance==parent2,1, 'first'); parent2Path = pop(parent2X(1,1),:); subPath = crossover(parent1Path, parent2Path, crossoverProbabilty);%交叉 subPath = mutate(subPath, mutationProbabilty);%变异 offspring(k,:) = subPath(1,:); minPathes(gen,1) = minPath; end fprintf('代数:%d 最短路径:%.2fKM \n', gen,minPath); % 更新 pop = offspring; % 画出当前状态下的最短路径 if minPath < gbest gbest = minPath; paint(cities, pop, gbest, sumDistance,gen); end end figure plot(minPathes, 'MarkerFaceColor', 'red','LineWidth',1); title('收敛曲线图(每一代的最短路径)'); set(gca,'ytick',500:100:5000); ylabel('路径长度'); xlabel('迭代次数'); grid on tEnd = toc(tStart); fprintf('时间:%d 分 %f 秒.\n', floor(tEnd/60), rem(tEnd,60));
完整代码参考我的网站:http://www.omegaxyz.com/2019/01/21/matlab-tsp-all/
结果
测试数据:

初始状态:

最终状态:

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/212562.html原文链接:https://javaforall.net
