当前位置: 首页 > news >正文

遗传算法求解旅行商问题分析

目录

一、问题分析

二、实现步骤

1)初始化种群

2)计算适应度

 3)选择操作

4)交叉操作

5)变异操作

三、求解结果

四、总结 


本文通过一个经典的旅行商问题,详细阐述在实际问题中如何运用遗传算法来进行分析求解。

一、问题分析

       旅行商问题抽象为数学描述为,在平面内有有限个点,寻找一条路径穿过所有点,使路径长度最短。这个问题描述很简单,其实想要求解也很简单,因为途径所有点的路径数量是有限的,我们可以采用穷举法计算每一条路径的距离值,然后得到最短路径。但是采用穷举法的可行性不高,当我们要途径几十个点时,所有路径的总数是n!,这是一个非常庞大的数字,穷举已经不现实。因此我们选择采用其他智能优化算法来求解该问题。

       那么应该如何选择计算方法呢?从上面的分析中我们已经知道,这是一个求解最优解问题,我们还知道这个问题的解是有限范围的,因此我们可以选择遗传算法来求解。下面我们将沿着遗传算法经典步骤,逐步详细说明如何用遗传算法来求解旅行商问题。

二、实现步骤

1)初始化种群

       在初始化种群前,我们首先应考虑如何根据实际问题来设计个体和种群。在旅行商问题中,个体也就是解表征的是一组城市的排列结果,这个解不是单个的数值,而是一个组合。如果我们将每个城市依次编号,那么这个解就是一个N维的向量,向量元素为1到N之间的整数,其中N为城市总数。这个向量非常类似于一个群体中的个体,它已经由基因(城市编号)组成。因此我们可以直接使用这个向量作为群体的个体。初始化群体的代码如下。

       我们定义种群个体数量为100,最大迭代代数为1000,初始种群的大小就是一个100×31(n_cities)的矩阵,n_cities表示个体的基因数,也是城市数量。第一个for循环完成了初始种群的赋值。

    % 遗传算法参数population_size = 100;    % 种群大小max_generations = 1000;    % 最大迭代次数crossover_rate = 0.8;      % 交叉概率mutation_rate = 0.1;       % 变异概率tournament_size = 5;       % 锦标赛选择大小elite_num = 2;             % 精英保留数目% 初始化种群population = zeros(population_size, n_cities);for i = 1:population_sizepopulation(i,:) = randperm(n_cities);end

2)计算适应度

       在旅行商问题中,我们的目标值只有一个,就是路径的距离最短。在得到一个种群之后,我们可以直接计算出种群中每个个体,即每种路径的距离值。显然,距离值越小,适应度越大。因此,可以使用距离的导数来表征个体适应度的大小。具体实现代码如下。distances为已经计算好的两两城市之间的距离,此处直接提出相加即可。

        % 计算适应度fitness = zeros(population_size, 1);for i = 1:population_sizefitness(i) = 1 / calculate_total_distance(population(i,:), distances);end
% 计算路径总长度
function total_dist = calculate_total_distance(path, distances)n = length(path);total_dist = 0;for i = 1:n-1total_dist = total_dist + distances(path(i), path(i+1));endtotal_dist = total_dist + distances(path(end), path(1));
end

 3)选择操作

       此处采用锦标赛法选择需要继承的父代。该方法的思想是随机从种群中抽取部分个体,然后将这部分个体中适应度最高的个体传递给下一代。此处直接选择两个父代的个体,以便直接进行后续的交叉和变异操作。

% 锦标赛选择父代
parent1 = tournament_selection(population, fitness, tournament_size);
parent2 = tournament_selection(population, fitness, tournament_size);
% 锦标赛选择
function selected = tournament_selection(population, fitness, tournament_size)candidates = randperm(size(population,1), tournament_size);[~, idx] = max(fitness(candidates));selected = population(candidates(idx), :);
end

4)交叉操作

        直接对选出的两个父代个体执行交叉操作。此处采用的交叉方法为顺序交叉法,其算法思想如下图所示。首先随机得到一个交叉区域,将个体P1中该区域的元素赋给新个体child1的对应区域位置,然后将P2以交叉区域后边界分为前后两段,并将前后两段互换位置得到一个新的片段,当然这个片段中删除了交叉区域中已经存在的元素,然后再将这个片段分别赋给child1的两端,不要覆盖交叉区域。这样就得到了交叉后的第一个新个体,然后交换P1和P2角色,执行上述操作,得到child2第二个个体,这样交叉操作就完成了。

% 交叉
if rand < crossover_rate[child1, child2] = ox_crossover(parent1, parent2);
elsechild1 = parent1;child2 = parent2;
end
% 顺序交叉 (OX)
function [child1, child2] = ox_crossover(parent1, parent2)n = length(parent1);points = sort(randperm(n, 2));start = points(1);end_ = points(2);% 子代1segment1 = parent1(start:end_);remaining = [];for i = [end_+1:n, 1:end_]city = parent2(i);if ~ismember(city, segment1)remaining = [remaining, city];endendchild1 = zeros(1, n);child1(start:end_) = segment1;child1([1:start-1, end_+1:n]) = remaining(1:n - (end_ - start + 1));  % 子代2segment2 = parent2(start:end_);remaining = [];for i = [end_+1:n, 1:end_]city = parent1(i);if ~ismember(city, segment2)remaining = [remaining, city];endendchild2 = zeros(1, n);child2(start:end_) = segment2;child2([1:start-1, end_+1:n]) = remaining(1:n - (end_ - start + 1));
end

5)变异操作

       此处变异使用简单的交换操作,即交换个体中任意两个位置的元素。具体实现代码如下,首先随机产生一个随机数,判断是否满足可变异概率,然后在随机生成两个位置,将这两个位置的元素进行交换即可。

% 变异
child1 = mutate(child1, mutation_rate);
child2 = mutate(child2, mutation_rate);
% 变异(交换)
function mutated = mutate(individual, mutation_rate)mutated = individual;if rand < mutation_raten = length(individual);pos = randperm(n, 2);mutated(pos(1)) = individual(pos(2));mutated(pos(2)) = individual(pos(1));end
end

三、求解结果

程序完整实现代码在这里。最终求解结果如下图所示,得到的最优距离为15598。

四、总结 

       通过遗传算法求解旅行商问题流程可知,遗传算法的各项具体操作实现方法不是固定不变的,需要根据实际问题分析处理。即使使用本文提供的实际程序计算,每次迭代计算得到的结果也是不一样的。旅行商问题本质上是一个排列问题,且越接近最优解时,解相邻元素的排列顺序越接近。根据这一特性,我们在进行交叉、变异产生新个体时就需要设计合适的算法实现,减小对排列顺序大幅度调整的概率。因此,我们以非常小的概率控制变异发生,在交叉过程中使用分段交叉,尽量保持相邻元素的排列顺序。总之,在遗传算法产生新的子代群体过程中,我们应尽量避免产生大量与上一代差异较大的个体,当然也尽可能保留少量差异大的个体,使种群始终向最优解方向缓慢进化,避免算法不收敛或陷入局部最优解中。

http://www.dtcms.com/a/191944.html

相关文章:

  • 【FMC216】基于 VITA57.1 的 2 路 TLK2711 发送、2 路 TLK2711 接收 FMC 子卡模块
  • [学习]RTKLib详解:tle.c(系列终章)
  • Android 图片自动拉伸不变形,点九
  • windows ffmpeg msvc x64编译
  • pytorch训练可视化工具---TensorBoard
  • 【web应用】配置Java JDK与maven3的环境变量
  • Docker实现MySQL数据库主从复制
  • 《棒球百科》市运会是什么级别的比赛·棒球1号位
  • nt!MiAllocateWsle函数分析之设置Wsle[WorkingSetIndex]
  • Golang
  • 基于策略的强化学习方法之近端策略优化(PPO)深度解析
  • 2025.05.14华为机考笔试题-第一题-100分
  • xp_cmdshell bcp 导出文件
  • 测试--BUG(软件测试⽣命周期 bug的⽣命周期 与开发产⽣争执怎么办)
  • 牛客网NC22157:牛牛学数列2
  • 编程题 03-树3 Tree Traversals Again【PAT】
  • AI实时对话的通信基础,WebRTC技术综合指南
  • GPU与NPU异构计算任务划分算法研究:基于强化学习的Transformer负载均衡实践
  • Go 语言中接口类型转换为具体类型
  • Automatic Recovery of the Atmospheric Light in Hazy Images论文阅读
  • RabbitMQ 消息模式实战:从简单队列到复杂路由(一)
  • 用FileCodeBox打造私有文件传输:Ubuntu环境保姆级部署教程!
  • python算法-最大连续1的个数删除有序数组中的重复项--Day020
  • go依赖查询工具之godepgraph(分析main.go的依赖树)
  • 2025.05.14华为机考笔试题-第二题-200分
  • 鸿蒙OSUniApp制作多选框与单选框组件#三方框架 #Uniapp
  • ET EntityRef EntityWeakRef 类分析
  • C#语法基础
  • 分布式调度的--多模型协同工作实践方案
  • 语音识别——声纹识别