用遗传算法求解TSP问题(Matlab)

一、实验目标

1、完成基于Matlab 的遗传算法的编写,并用于测试旅行商问题,给出结果

2、 掌握遗传算法的基本流程
3、 掌握 TSP 问题的数据化处理
4、 掌握适应度函数编写
5、 掌握交叉、变异和选择操作编写

二、实验内容

1、 将例子中城市的个数扩充到 30 个

%城市坐标

map=[18,54;87,76;74,78;71,71;25,38;58,35;4,50;13,40;18,40;24,42;

    71,44;64,60;68,58;83,69;58,69;54,62;51,67;37,84;14,94;2,99;

    7,64;22,60;25,62;62,32;87,7;91,38;83,46;41,26;45,21;44,35];

2、 将例子中的选择算子改成轮盘赌实现。

% 调用函数进行轮盘赌选择操作

Road = chooseParentsRoulette(Road, fitness);

3、 将例子中的顺序交叉改成下图所示的顺序交叉方法

% 调用顺序交叉函数

children = [];

for i=1:Popsize

    if rand<pc  %rand(1)小于1的随机数

        sgpoint=randi(n,2,1); %获得1-n中的随机数,数量为2

        minsg=min(sgpoint);

        maxsg=max(sgpoint);

        x=randi(Popsize,2,1); %调用randi函数,获得[1:Popsize]中的两个随机数

        parent1=Road(x(1),:);%获得两个交叉用父代

        parent2=Road(x(2),:);

        child = sequentialCrossover(parent1, parent2);

        children = [children; child];

    end



end

4、 将例子中计算路径长度的语句用调用函数的形式实现

% 调用函数计算路径长度

Dist = calculatePathLengths(children, map, @distance);

5、 结果展示中,画出一条初始路径、一条全局最优路径和迭代曲线

% 绘制初始路径

figure;

subplot(2, 1, 1);

plot(map(:,1), map(:,2), 'ro');

hold on;

plot([map(Road(1,:),1); map(Road(1,1),1)], [map(Road(1,:),2); map(Road(1,1),2)], 'b-');

title('初始路径');

xlabel('X坐标');

ylabel('Y坐标');



% 绘制全局最优路径

subplot(2, 1, 2);

plot(map(:,1), map(:,2), 'ro');

hold on;

plot([map(MinRoad(Iterindex,:),1); map(MinRoad(Iterindex,1),1)], [map(MinRoad(Iterindex,:),2); map(MinRoad(Iterindex,1),2)], '*-');

title('全局最优路径');

xlabel('X坐标');

ylabel('Y坐标');



% 绘制迭代曲线

figure;

plot(1:MaxIter, MinRoad_value, 'b-');

title('迭代曲线');

xlabel('迭代次数');

ylabel('最短路径长度');

三、实验总结

通过运行我们的遗传算法程序,我们得到了30个城市TSP问题的解。在结果展示中,我们也绘制了初始路径、全局最优路径和迭代曲线。通过对比和分析这些结果,我们可以得出以下结论:

  1. 遗传算法能够有效地解决TSP问题。
    通过运行我们的程序,我们得到了一个相对较优的解,这表明遗传算法是一种解决TSP问题的有效方法。
  2. 增加城市数量对算法性能有一定影响。
    在本次实验中,我们将城市数量扩展到30个,增加了一定的计算量和复杂性。但是我们的算法仍然能够得到较好的结果,这说明我们的算法具有一定的扩展性和鲁棒性。

四、代码附录

运行代码

%parameters

%城市坐标

map=[18,54;87,76;74,78;71,71;25,38;58,35;4,50;13,40;18,40;24,42;

    71,44;64,60;68,58;83,69;58,69;54,62;51,67;37,84;14,94;2,99;

    7,64;22,60;25,62;62,32;87,7;91,38;83,46;41,26;45,21;44,35];



n=max(size(map));  % the number of cities

pc=0.8;  %交叉概率,相当于基因遗传的时候染色体交叉

pm=0.1;  %染色体变异

MaxIter=200;  %允许迭代最大次数

Popsize=150;  %群体的大小



% initialize population

for i=1:Popsize

    Road(i,:)=randperm(n); %产生自然数1到n的一个随机排列

end



Iter=1;

MinRoad=zeros(MaxIter,n);

MinRoad_value=zeros(MaxIter,1);

fitness=zeros(MaxIter,1);

while(Iter<=MaxIter)



%计算每条路径的长度

% 调用函数计算路径长度



for i =1:Popsize

    route(1,:)=[Road(i,:),Road(i,1)];

end

Dist = calculatePathLengths(Road, map, @distance);



[Mindist,q]=min(Dist);   %在Dist中,找出最短路径长度

Maxdist=max(Dist);

MinRoad_parents=Road(q,:);%存入MinRoad_parents_value,并得到该最短路径

MinRoad_parents_value=Mindist;%将它存入MinRoad_parents



for i=1:Popsize

fitness(i)=1-(Dist(i)-Mindist)/(Maxdist-Mindist);

%计算每条路径的适应度函数,存入fitness, fitness大小为Popsize*1

%最小值问题转成最大值问题,并进行归一化处理

end





% 调用函数进行轮盘赌选择操作

Road = chooseParentsRoulette(Road, fitness);



% 调用顺序交叉函数

children = [];

for i=1:Popsize

    if rand<pc  %rand(1)小于1的随机数

        sgpoint=randi(n,2,1); %获得1-n中的随机数,数量为2

        minsg=min(sgpoint);

        maxsg=max(sgpoint);

        x=randi(Popsize,2,1); %调用randi函数,获得[1:Popsize]中的两个随机数

        parent1=Road(x(1),:);%获得两个交叉用父代

        parent2=Road(x(2),:);

        child = sequentialCrossover(parent1, parent2);

        children = [children; child];

    end



end



% 调用函数计算路径长度

Dist = calculatePathLengths(children, map, @distance);



[Mindist,q]=min(Dist);

MinRoad_crossover=Road(q,:);

MinRoad_crossover_value=Mindist;

  

 % mutation变异

 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 = calculatePathLengths(Road, map, @distance);



[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(2, 1, 1);

plot(map(:,1), map(:,2), 'ro');

hold on;

plot([map(Road(1,:),1); map(Road(1,1),1)], [map(Road(1,:),2); map(Road(1,1),2)], 'b-');

title('初始路径');

xlabel('X坐标');

ylabel('Y坐标');



% 绘制全局最优路径

subplot(2, 1, 2);

plot(map(:,1), map(:,2), 'ro');

hold on;

plot([map(MinRoad(Iterindex,:),1); map(MinRoad(Iterindex,1),1)], [map(MinRoad(Iterindex,:),2); map(MinRoad(Iterindex,1),2)], '*-');

title('全局最优路径');

xlabel('X坐标');

ylabel('Y坐标');



% 绘制迭代曲线

figure;

plot(1:MaxIter, MinRoad_value, 'b-');

title('迭代曲线');

xlabel('迭代次数');

ylabel('最短路径长度');

calculatePathLengths.m

function Dist = calculatePathLengths(Road, map, distance)

    % 计算每条路径的长度

   

    [Popsize, n] = size(Road);

    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

chooseParentsRouLette.m

function Road = chooseParentsRoulette(Road, fitness)

    % 选择操作:使用轮盘赌选择父代路径



    Popsize = size(Road, 1);

    totalFitness = sum(fitness);

    selectionProb = fitness / totalFitness;



    % 计算累积概率

    cumProb = cumsum(selectionProb);



    % 选择父代路径

    newRoad = zeros(size(Road));

    for i = 1:Popsize

        r = rand;

        for j = 1:Popsize

            if r <= cumProb(j)

                newRoad(i, :) = Road(j, :);

                break;

            end

        end

    end

   

    Road = newRoad;

end

distance.m

function d=distance(A,B)  %计算两城市之间距离函数

d=sqrt((A(1)-B(1))^2+(A(2)-B(2))^2); %距离公式

end

eliminate.m

function  elim=eliminate(x,y)



for n=1:length(y)

    x=x(find(x~=y(n))); %去除x中的y

end

elim=x;

end



fitness.m

function f=fitness(fmin,fmax,froad)

f=1-(froad-fmin)/(fmax-fmin);       %适应度函数

end

plotResults.m

function plotResults(initialPath, bestPath, iteration, distances)

    % 绘制初始路径、全局最优路径和迭代曲线

   

    figure;

   

    % 绘制初始路径

    subplot(1, 2, 1);

    plotPath(initialPath, '初始路径');

   

    % 绘制全局最优路径

    subplot(1, 2, 2);

    plotPath(bestPath, '全局最优路径');

   

    % 绘制迭代曲线

    figure;

    plot(iteration, distances, 'b.-');

    xlabel('迭代次数');

    ylabel('最短路径长度');

    title('迭代曲线');

end



function plotPath(path, titleText)

    x = path(:, 1);

    y = path(:, 2);

    x = [x; x(1)]; % 将路径首尾相连形成闭环

    y = [y; y(1)];

    plot(x, y, 'r.-');

    xlabel('X坐标');

    ylabel('Y坐标');

    title(titleText);

    axis equal;

end

sequentialCrossover.m

function child = sequentialCrossover(parent1, parent2)
    % 顺序交叉操作:从第一双亲随机选择一个字串,通过拷贝子串产生原始后代
    
    n = length(parent1);
    
    % 从第一双亲中随机选择一个字串
    startIdx = randi([1, n-1]);
    endIdx = randi([startIdx+1, n]);
    
    % 拷贝子串生成原始后代
    child = zeros(1, n);
    child(startIdx:endIdx) = parent1(startIdx:endIdx);
    
    % 删除第二双亲中已有的城市
    for i = startIdx:endIdx
        parent2(parent2 == child(i)) = 0;
    end
    
    % 将剩余的城市按顺序填入后代的空缺位置
    child(child == 0) = parent2(parent2 ~= 0);
end
  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值