蚁群算法

天大地大妈咪最大 提交于 2019-11-27 07:15:53

TSP问题(Traveling Salesman Problem)是数学领域中著名问题之一。假设有一个旅行商人要拜访N个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次(通过禁忌表),而且最后要回到原来出发的城市,要求路径的总和最小

蚁群算法(AG)是一种模拟蚂蚁觅食行为的模拟优化算法,首先使用在解决TSP(旅行商问题)上。

人工蚁群与真实蚁群对比:

相同点 不同点
都是为了寻找最短路径问题 人工蚁群具有记忆功能
都存在个体间的信息交互问题 人工蚁群的选择并不盲目性
都采用根据当前的信息进行随机选择策略 人工蚂蚁生活在离散的时间环境中

代码部分:
蚁群算法实现核心有两点:1,蚂蚁如何选择下一个城市;2,城市间路径信息素如何更新。

a. 计算城市之间的转移概率:
在这里插入图片描述

% 计算城市之间的转移概率
for k = 1:length(allow)
P(k) = Tau(tabu(end),allow(k))^alpha * Eta(tabu(end),allow(k))^beta;
%等式的分子
End
P = P/sum(P);  %上面等式的分母部分

在计算出来城市之间的转移概率之后还要用轮盘赌法的原因:
在得到剩下去城市概率,产生一个随机数,基于随机数决定去下面哪一个城市。例如:剩3个城市,概率为:0.1,0.2,0.7,累计概率为:0.1,0.3,0.7,产生一个随机数,随机数为0.21(介于0.1到0.3之间),则去城市2(偏向于选择最大的)。此过程则为轮盘赌,又可说其服从蚁群算法会优先去概率大的地方,但还是随机走。
原文:https://blog.csdn.net/Sue_qx/article/details/82149965

蚁群算法:

>> %%%蚁群算法解决TSP问题%%%%%%%

clear all; %清除所有变量
close all; %清图
m=50;% m 蚂蚁个数
Alpha=1; %%Alpha 表征信息素重要程度的参数
Beta=5; %Beta 表征启发式因子重要程度的参数
Rho=0.1; %%Rho 信息素蒸发系数
NC_max=200; %%最大迭代次数
Q=100; %%信息素增加强度系数
C=[1304 2312;3639 1315;4177 2244;3712 1399;3488 1535;3326 1556;3238 1229;4196 1004;4312 790;4386 570;3007 1970;2562 1756;2788 1491;2381 1676;1332 695;3715 1678;3918 2179;4061 2370;3780 2212;3676 2578;4029 2838;4263 2931;3429 1908;3507 2367;3394 2643;3439 3201;2935 3240;3140 3550;2545 2357;2778 2826;2370 2975];                %%31个省会坐标
%% 主要符号说明
%% C n个城市的坐标,n*2的矩阵
%% NC_max 最大迭代次数
%% m 蚂蚁个数
%% Alpha 表征信息素重要程度的参数
%% Beta 表征启发式因子重要程度的参数
%% Rho 信息素蒸发系数
%% R_best 各代最佳路线
%% L_best 各代最佳路线的长度

%% 第一步:变量初始化
n=size(C,1);%n表示问题的规模(城市个数)         //求出城市的个数
D=zeros(n,n);%D表示完全图的赋权邻接矩阵        //用来生成n行n列的零
for i=1:n
     for j=1:n
         if i~=j % ~=相当于C中的!=,即不等于
            D(i,j)=((C(i,1)-C(j,1))^2+(C(i,2)-C(j,2))^2)^0.5;    % //D在这里表示的是距离(一个城市到 下一个城市)  当执行一次i,执行n次j时表示的是第一个城市到其他城市的距离。
         else 
            D(i,j)=eps; %i=j时不计算,应该为0,但后面的启发因子要取倒数,用eps(浮点相对精度)表示                           意思是同一个省会城市之间的距离为零
         end
         D(j,i)=D(i,j); %对称矩阵
     end
end
Eta=1./D; %Eta为启发因子,这里设为距离的倒数
Tau=ones(n,n); %Tau为信息素矩阵                //矩阵n*n全部赋值为1
Tabu=zeros(m,n);%存储并记录路径的生成          //矩阵n*n全部赋值为0
NC=1; %迭代计数器,记录迭代次数
R_best=zeros(NC_max,n); %各代最佳路线
L_best=inf.*ones(NC_max,1); %各代最佳路线的长度   //Inf*ones(1,N) 1、inf代表正无穷,是一个数字                        2、ones(1,N)代表建立一个矩阵,这个矩阵元素全是1,矩阵的尺寸是1行×N列
                      % 3、两者相乘的结果为一个矩阵,该矩阵尺寸也为1行×N列,只不过元素全为正无穷inf 
L_ave=zeros(NC_max,1); %各代路线的平均长度     //比如a=zeros(3,5);就是创建一个3行5列的0矩阵


while NC<=NC_max %停止条件之一:达到最大迭代次数,停止
  
%%第二步:将M只蚂蚁放到N个城市上
   Randpos=[]; %随即存取
   for i=1:(ceil(m/n))                        % //ceil 是向离它最近的大整数圆整. 如a = [-1.9, -0.2, 3.4, 5.6, 7, 2.4+3.6i]  圆整后:a=[-1,0, 4, 6, 7 ,3+4i]
       Randpos=[Randpos,randperm(n)];          %//randperm的函数功能:随机打乱一个数字序列
   end
   Tabu(:,1)=(Randpos(1,1:m))';

%//蚂蚁重复城市的次数,比如5个蚂蚁放到4个城市,需要重复两遍才能放完蚂蚁,每次循环产生n个1---n的随机数,相当于随机n个城市,产生城市序列(城市序号出现的次数代表的是有几只蚂蚁在这座城市)
% 循环结束
% Tabu一句表示将m个蚂蚁随机,每个蚂蚁放到前面产生的城市序列中,每个蚂蚁一个城市,需要m个,所以提取前面1:m个序列                         
% '表示转置,没有多大用处,可能参与后面的计算方便。
% 我感觉如果m,n很大的话,你这样做会产生很大的浪费,计算很多的随机数,这样的话更好,一句就得:(如果变量Randpos后面没有用到的话,如果用到了,还要用你的程序)




    
     %%第三步:m只蚂蚁按概率函数选择下一座城市,完成各自的周游
     for j=2:n %所在城市不计算
         for i=1:m  %一只一只访问城市
             visited=Tabu(i,1:(j-1)); %记录已访问的城市,避免重复访问
             J=zeros(1,(n-j+1)); %待访问的城市
             P=J; %待访问城市的选择概率分布
             Jc=1; 
             for k=1:n
               if length(find(visited==k))==0 %开始时置0
                    J(Jc)=k;
                    Jc=Jc+1;   %访问的城市个数自加1
               end
             end
             %下面计算待选城市的概率分布
             for k=1:length(J)  
                P(k)=(Tau(visited(end),J(k))^Alpha)*(Eta(visited(end),J(k))^Beta);  
             end  
             P=P/(sum(P)); %按概率原则选取下一个城市
             Pcum=cumsum(P); %cumsum,元素累加即求和
             Select=find(Pcum>=rand); %若计算的概率大于原来的就选择这条路线
             to_visit=J(Select(1));
             Tabu(i,j)=to_visit;
          end
      end
if NC>=2  % 迭代次数NC
   Tabu(1,:)=R_best(NC-1,:);
end

%%第四步: 记录本次迭代最佳路线长度
L=zeros(m,1);%开始距离为0,m*1的列向量
for i=1:m
   R=Tabu(i,:);
   for j=1:(n-1)
      L(i)=L(i)+D(R(j),R(j+1)); %原距离加上第j个城市到第j+1个城市的距离
   end
      L(i)=L(i)+D(R(1),R(n));   %一轮下来后走过的距离
   end
L_best(NC)=min(L);  %最佳距离取最小
pos=find(L==L_best(NC));
R_best(NC,:)=Tabu(pos(1),:);%此轮迭代后的最佳路线
L_ave(NC)=mean(L);%此轮迭代后的平均距离
NC=NC+1; %迭代继续


%%第五步:更新信息素
Delta_Tau=zeros(n,n); %开始时信息素为n*n的矩阵
for i=1:m
  for j=1:(n-1)
    Delta_Tau(Tabu(i,j),Tabu(i,j+1))=Delta_Tau(Tabu(i,j),Tabu(i,j+1))+Q/L(i); %此次循环在路径(i,j)上的信息素增量 
  end
  Delta_Tau(Tabu(i,n),Tabu(i,1))=Delta_Tau(Tabu(i,n),Tabu(i,1))+Q/L(i); %此次循环在整个路径上的信息素增量
end

Tau=(1-Rho).*Tau+Delta_Tau; %考虑信息素挥发,更新后的信息素


%%第六步:禁忌表清零
Tabu=zeros(m,n);  %%直到最大的迭代次数
end

%%第七步:输出结果
Pos=find(L_best==min(L_best)); %找到最佳路径(非0为真)
Shortest_Route=R_best(Pos(1),:) %最大迭代次数后最佳路径
Shortest_Length=L_best(Pos(1)) %最大迭代次数后最短距离

figure(1)
plot(L_best)
xlabel('迭代次数')
ylabel('目标函数值')
title('适应度进化曲线')

figure(2)
subplot(1,2,1)    %绘制第一个子图形
%% subplot(m,n,p)生成m*n个子图,当前激活第p个子图
%画路线图
%%============================================================
%% DrawRoute.m
%%画路线图
%%————————————————————————————
%% C Coordinate 节点坐标,由一个N*2的矩阵存储
%% R Route 路线
%%============================================================
N=length(R);
scatter(C(:,1),C(:,2));
hold on
%% scatter(X,Y) 中 X和Y是数据向量,以X中数据为横坐标,以Y中数据位纵坐标描绘散点图,点的形状默认使用圈

plot([C(R(1),1),C(R(N),1)],[C(R(1),2),C(R(N),2)],'g')
hold on

for ii=2:N
plot([C(R(ii-1),1),C(R(ii),1)],[C(R(ii-1),2),C(R(ii),2)],'g')
hold on 
end

title('旅行商问题优化结果')
 
subplot(1,2,2)  %绘制第二个子图
plot(L_best)
hold on  %保持图形
plot(L_ave,'r')
title('平均距离和最短距离')   %标题

在这里插入图片描述
在这里插入图片描述

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!