【遗传算法求解TSP问题】matlab实现

问题描述

旅行商问题(Traveling Salesman Problem,TSP)是一个著名的组合优化问题,其目标是找到一条最短路径,使得旅行商可以经过所有给定城市一次并回到起始城市。在这个问题中,假设有一位旅行商要访问多个城市,并且每两个城市之间都有确定的距离或成本。TSP的目标是找到一条路径,使得旅行商走过的总距离或总成本最小。

遗传算法

在这里插入图片描述
具体算法原理参考计算智能

代码实现

% 按表格定义城市坐标
% 按表格定义城市坐标
map = [18, 54; 87, 76; 74, 78; 71, 71; 25, 38; 58, 35; 04, 50; 13, 40; 18, 40; 24, 42;
       71, 44; 64, 60; 68, 58; 83, 69; 58, 69; 54, 62; 51, 67; 37, 84; 41, 94; 02, 99;
       07, 64; 22, 60; 25, 62; 62, 32; 87, 07; 91, 38; 83, 46; 41, 26; 45, 21; 44, 35];

n = max(size(map)); % 城市数
pc = 0.8; % 交叉概率
pm = 0.1; % 变异概率
MaxIter = 500; % 迭代次数
Popsize=150;% 染色体数/种群个体数
% 初始化祖先基因,150行30列的0矩阵
Road = zeros(Popsize, n);
for i = 1:Popsize
 Road(i,:) = randperm(n);%产生1-30的随机序列进行打乱
end
Iter = 1;
MinRoad = zeros(MaxIter, n);%保存每次迭代的最短路径(城市序号排列)
MinRoad_value = zeros(MaxIter, 1);%保存每次迭代最短路径值
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%迭代主循环%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
while(Iter <= MaxIter)
    Dist = calculateDistances(Road, map);%根据实际坐标计算每一条随机路径的长度
    [Mindist, q] = min(Dist);%取距离最短的值Mindist以及序号q
    Maxdist = max(Dist);%取距离最长的值Maxdist
    MinRoad_parents = Road(q, :);
    MinRoad_parents_value = Mindist;
    % 利用最大最小值为每一个个体计算适应度(1行150列)
    fitness = zeros(1, Popsize);
 
    for i = 1:Popsize
        fitness(i) = 1 - (Dist(i) - Mindist) / (Maxdist - Mindist);
    end
 
   % 对适应度进行从小到大排序,f为排序后适应度,p为排序后原本序号
    [f, p] = sort(fitness);
    % 使用轮盘赌选出同等数量的路径并替换
    selected_indices = roulette_wheel_selection(f, Popsize);
    for i = 1:Popsize
        Road(p(i), :) = Road(p(selected_indices(i)), :);
    end
 
    % 交叉
    for i=1:Popsize
        if rand<pc %rand(1)小于 1 的随机数
            % 随机选择两个父代
            x = randi(Popsize,2,1);
            parent1 = Road(x(1),:);
            parent2 = Road(x(2),:);
            % 使用顺序交叉获得子代
            [parent1_new, parent2_new] = order_crossover(parent1, parent2);
            Road(x(1), :) = parent1_new;
            Road(x(2), :) = parent2_new;
        end
    end
 
    % 计算交叉后路径的长度,并找出最小路径
    Dist = calculateDistances(Road, map);
 
    [Mindist, q] = min(Dist);
    MinRoad_crossover = Road(q, :);
    MinRoad_crossover_value = Mindist;
 
    % 变异
    for i = 1:Popsize
        if rand < pm && i ~= q % 不对最优路径进行变异
            mupoint = randi(n, 1, 2);
            temp_point = Road(i, mupoint(1));
            Road(i, mupoint(1)) = Road(i, mupoint(2));
            Road(i, mupoint(2)) = temp_point;
        end
    end
 
    % 计算变异后路径的长度,并找出最小路径
    Dist = calculateDistances(Road, map);
 
    [Mindist, q] = min(Dist);
    MinRoad_mutation = Road(q, :);
    MinRoad_mutation_value = Mindist; 
 
    % 每一代中找到的最优路径
    MinRoad_opt = [MinRoad_parents; MinRoad_crossover; MinRoad_mutation];
    a = [MinRoad_parents_value; MinRoad_crossover_value; MinRoad_mutation_value];
    [Minvalue ,m] = min(a);
    MinRoad(Iter, :) = MinRoad_opt(m, :);
    MinRoad_value(Iter, 1) = Minvalue;
    Iter = Iter + 1;
end
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%画图部分%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 找出全局最优路径及其迭代次数
[MinestRoad_value, Iterindex] = min(MinRoad_value);
disp('最优路径为:');
disp(MinRoad(Iterindex, :));
disp('最优路径长度为:');
disp(MinestRoad_value);
disp('获得最佳路径的迭代次数为:');
disp(Iterindex);
% 城市路径图
figure;
% 初始路径
subplot(1, 2, 1);
draw_map = [map; map(1, :)];
plot(draw_map(:, 1), draw_map(:, 2), '*', 'DisplayName', '城市');
hold on;
plot(draw_map(:, 1), draw_map(:, 2), '-', 'LineWidth', 1, 'Color', [1, 0.5, 0],'DisplayName', '初始路径');
legend('show');
legend('Location', 'best');
for c = 1:n
    text(map(c, 1), map(c, 2), [' ' num2str(c)], 'Color', 'k', 'FontWeight', 'b');
end
% 最优路径
subplot(1, 2, 2);
ordered_map = map(MinRoad(Iterindex, :), :);
ordered_map = [ordered_map; ordered_map(1, :)];
plot(ordered_map(:, 1), ordered_map(:, 2), '*', 'DisplayName', '城市');
hold on;
plot(ordered_map(:, 1), ordered_map(:, 2), '-', 'LineWidth', 1, 'Color', [1, 0.5, 0],'DisplayName', '最优路径');
legend('show');
legend('Location', 'best');
for c = 1:n
    text(ordered_map(c, 1), ordered_map(c, 2), [' ' num2str(c)], 'Color', 'k','FontWeight', 'b');
end
% 迭代曲线图
figure;
plot(MinRoad_value);
title('迭代曲线');
xlabel('迭代次数');
ylabel('最短路径长度');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%工具函数部分%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 计算路径总长度
function Dist = calculateDistances(Road, map)
    Popsize = size(Road, 1); % 群体大小
    n = size(Road, 2); % 节点数量
    Dist = zeros(Popsize, 1); % 用于存储每条路径的距离
    for i = 1:Popsize
        dist = 0;
        for j = 1:(n - 1)
            A = Road(i, j);
            B = Road(i, j + 1);
            A1 = map(A, :);
            B1 = map(B, :);
            dist = dist + distance(A1, B1);
        end
         A = Road(i, 1);
         B = Road(i, n);
         A1 = map(A, :);
         B1 = map(B, :);
         dist = dist + distance(A1, B1);
         Dist(i, 1) = dist;
    end
end
% 计算两城市之间距离
function d = distance(A, B)
    d = sqrt((B(1) - A(1))^2 + (B(2) - A(2))^2);
end
% 轮盘赌
function selected_indices = roulette_wheel_selection(f, num_selections)
     selected_indices = zeros(1, num_selections);
     % 对适应度进行归一化
     nf = f / sum(f);
     % 选择 n 次
     for iter = 1:num_selections
         total_prob = 0;
         randNum = rand();
         % 计算累计概率,符合条件的则选择
         for i = 1:length(nf)
             total_prob = total_prob + nf(i);
             if total_prob > randNum
                 selected_indices(iter) = i;
                 break;
            end
        end
    end
end
% 顺序交叉
function [child1, child2] = order_crossover(parent1, parent2)
     % 生成两个子代基因,初始化为-1
     child1 = -ones(size(parent1));
     child2 = -ones(size(parent2));
     % 随机选择交叉的起始和结束位置
     cp = sort(randi(length(parent1), 1, 2));
     % 复制父代中交叉区域的基因到子代
     child1(cp(1):cp(2)) = parent1(cp(1):cp(2));
     child2(cp(1):cp(2)) = parent2(cp(1):cp(2));
     % 补充缺失的基因到子代,按照父代中未被选择的顺序
     child1(child1 == -1) = parent2(~ismember(parent2, child1));
     child2(child2 == -1) = parent1(~ismember(parent1, child2));
end

输出结果

初始路径和最优路径对比图
在这里插入图片描述

迭代曲线图
在这里插入图片描述
最佳路径以及长度
在这里插入图片描述

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值