數學建模:matlab蟻羣算法解決TSP問題

蟻羣算法的來源

很久以前,生物學家就對螞蟻捕食行爲很好奇。因爲,可能大家不知道,螞蟻的視力特別差,你可以把它當成瞎子,可是每次卻都能找到食物,並且從它所找到的路徑,還是從洞穴到食物的最短路徑。大家可以想一想,每次你的桌子上有掉一顆糖,過不了多久,就立馬有螞蟻出現了,而且還是一成羣的螞蟻沿着同一條線路過來的。這是爲什麼呢?難道是螞蟻的鼻子很靈敏嗎?

後來生物學家們經過長時間的研究發現,並不是螞蟻的鼻子很靈敏,而是他們之間有一種很特別的信息傳遞方式——信息素,正是這種特別的信息傳遞方式,使得螞蟻這種生物,不會迷路。

言歸正傳,這個信息素是怎麼用的呢?其實是這樣的,螞蟻在行走的過程會釋放一種化學物質,這種化學物質就叫“信息素”,這是用來標識自己的行走路徑。而在尋找食物的過程中,螞蟻根據這個信息素的濃度來選擇行走的方向,最終就到達了食物的所在地。

更形象的理解一下蟻羣算法

在這裏插入圖片描述
假設螞蟻們在A點,食物在B點,螞蟻要去食物有兩條路徑,即路徑a和路徑b。現在A點有兩隻螞蟻要去取食物,假設兩隻螞蟻分別名字分別爲螞蟻a和螞蟻b,即螞蟻a沿a路徑走,螞蟻b沿b路徑走。

現在咱們假設兩隻螞蟻的速率、留下信息素速率和信息素揮發速率是一樣的。

那麼顯然螞蟻a比螞蟻b更快到達B點,即a路徑的信息素已經佈滿a路徑(假設在a路徑最開始端的信息素沒有揮發完),那麼b路徑的信息素目前只分布到一半(可能到紅叉之前),那麼現在螞蟻a開始取上食物往回走。
在這裏插入圖片描述
螞蟻a往回走會選擇信息素濃度高的路徑,即a路徑,那麼螞蟻a沿原路徑回到A點的路上時,螞蟻b到達B點,螞蟻b也要取上食物往回走,也要沿信息素濃度最高的路徑走,因爲a路徑螞蟻a走過兩次,所以信息素濃度比b路徑高,那麼螞蟻b也會沿着a路徑往回走,那麼此時a路徑的濃度又會增加。

那麼,每當以後有螞蟻要從A點去B點取食物,便會沿着信息素濃度高的路徑,即a路徑,那麼a路徑的信息素濃度也會越來越高。那麼信息素最多的路徑即爲最短路徑。

蟻羣算法與TSP問題的關係

蟻羣算法就是螞蟻尋找食物的過程,而把多個食物放在不同的地方,就是著名的TSP(Traveling Salesman Problem)問題,而信息素分佈最的路線就是最短的路徑。

螞蟻算法的基本原理

  1. 每隻螞蟻從一個城市走到另一個城市的過程中都會在路徑上釋放信息素,並且螞蟻選擇下一個城市的依據是一個概率公式,如下:
    Pijk(t)={τijα(t)ηijβ(t)stabukτisα(t)ηisβ(t),jtabuk0                    ,othersP^k_{ij}(t)= \left\{ \begin{aligned} \frac {\tau^\alpha_{ij}(t)\eta^\beta_{ij}(t)}{\sum_{s\notin tabu_k}\tau ^\alpha _{is}(t)·\eta ^\beta_{is}(t) }, j \notin tabu_k\\0~~~~~~~~~~~~~~~~~~~~,others \end{aligned} \right.
      上式中,各個符號的意義如下:

αβdijij;ηij(t)ηij(t)=1dijtabukkτijij\alpha-- 信息素啓發式因子,它反映了信息素對螞蟻路徑選擇的作用;\\ \beta -- 期望啓發式因子,它反映了信息素在螞蟻選擇路徑時被重視的程度;\\ d_{ij} -- 城市i和j之間的距離;\\ \eta_{ij}(t)-- 啓發函數,表達式爲\eta_{ij}(t)=\frac{1}{d_{ij}};\\ tabu_k -- 禁忌表,記錄螞蟻k當前所走過的城市;\\ \tau_{ij} -- 城市i到城市j的路徑上的信息素的量;\\

2. 螞蟻留下的信息素,因爲是化學物質,因此隨着時間的過去信息素也應該要以一定的速率揮發。根據不同的規則我們可以將蟻羣算法分爲三種模型——蟻周模型(Ant-Cycle)、蟻量模型(Ant-Quantity)和蟻密模型(Ant-Density)。
 
區別:
(1).蟻周模型利用的是全局信息,即螞蟻完成一個循環後更新所有路徑上的信息素;
(2).蟻量和蟻密模型利用的是局部信息,即螞蟻完成一步後更新路徑上的信息素。

通常使用的是蟻周模型,故本文只介紹蟻周模型。
 
根據上面所提供的信息,我們可以知道,當所有的螞蟻完成一次路徑循環後,才更新信息素。因此路徑上的信息素應該分爲兩部分:之前未揮發所殘留的信息素 + 經過當前循環所有螞蟻在經過該路徑後所留下的信息素。用公式表述如下:
τ(t+n)=(1ρ)τij(t)+Δτij(t,t+n)Δτij(t,t+n)=k=1mΔτijk(t,t+n)\tau (t+n)=(1-\rho)·\tau_{ij}(t)+\Delta \tau_{ij}(t,t+n)\\ \Delta \tau_{ij}(t,t+n)=\sum^m_{k=1} \Delta \tau^k_{ij}(t,t+n)
ρρ[0,1)ρ[0,1)Δτij(t,t+n)ij  (t,t+n)nΔτijk(t,t+n)k 其中, \rho -- 信息素揮發因子,ρ∈[0,1)ρ∈[0,1);\\ Δτ_{ij}(t,t+n) -- 經過一次循環後城市i到城市j的路徑上的信息素的增量;  \\ (t,t+n) -- 走過n步以後螞蟻即完成一次循環;\\ Δτ_{ij}^k(t,t+n) -- 表示經過一次循環後螞蟻k在它走過的路上的信息素增量。\\
 好了,現在我們的未揮發所殘留的信息素很好解,定義一個信息素揮發因子ρρ便能解決。但是,經過一次循環所有螞蟻留下的信息素該怎麼定義?在蟻周模型中,它被定義如下:
Δτijk(t,t+n)={QLk                   Antkwalkthoughpath(i,j)0                                                          other\Delta \tau^k_{ij}(t,t+n)= \left\{ \begin{aligned} \frac {Q}{L_k} ~~~~~~~~~~~~~~~~~~~Ant k walk though path (i,j)\\0~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ other \end{aligned} \right.
  它表明,螞蟻留下的信息素跟它走過的完整路徑的總長度有關。越長則留下的信息素越少,這個應該很好理解。爲了找到更短的路徑,就應該讓短的路徑信息素濃度高些。

3.蟻羣算法基本步驟
(1) 參數初始化:

通常可以按照以下策略來進行參數組合設定:

確定螞蟻數目
參數粗調:即調整取值範圍較大的α,β及Q;
參數微調:即調整取值範圍較小的ρ;
(2) 隨機將螞蟻放於不同出發點,對每隻螞蟻計算其下個訪問城市,直到所有螞蟻訪問完所有城市。
(3)計算螞蟻經過的路徑長度
(4) 判斷是否達到最大迭代次數,若否,返回步驟2;是,結束程序。
(5) 輸出結果,並根據需要輸出尋優過程中的相關指標,如運行時間、收斂迭代次數等。

matlab解決TSP問題的代碼

下面是各個地方的xy座標

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

%% 蟻羣算法求解TSP問題


%% 清空環境變量
clear 
clc

%% 導入數據
load citys_data.mat

%% 計算城市間相互距離
n = size(citys,1);
D = zeros(n,n);
for i = 1:n
    for j = 1:n
        if i ~= j
            D(i,j) = sqrt(sum((citys(i,:) - citys(j,:)).^2));
        else
            D(i,j) = 1e-4;      
        end
    end    
end

%% 初始化參數
m = 50;                              % 螞蟻數量
alpha = 1;                           % 信息素重要程度因子
beta = 5;                            % 啓發函數重要程度因子
rho = 0.1;                           % 信息素揮發因子
Q = 1;                               % 常係數
Eta = 1./D;                          % 啓發函數
Tau = ones(n,n);                     % 信息素矩陣
Table = zeros(m,n);                  % 路徑記錄表
iter = 1;                            % 迭代次數初值
iter_max = 200;                      % 最大迭代次數 
Route_best = zeros(iter_max,n);      % 各代最佳路徑       
Length_best = zeros(iter_max,1);     % 各代最佳路徑的長度  
Length_ave = zeros(iter_max,1);      % 各代路徑的平均長度  

%% 迭代尋找最佳路徑
while iter <= iter_max
    % 隨機產生各個螞蟻的起點城市
      start = zeros(m,1);
      for i = 1:m
          temp = randperm(n);
          start(i) = temp(1);
      end
      Table(:,1) = start; 
      % 構建解空間
      citys_index = 1:n;
      % 逐個螞蟻路徑選擇
      for i = 1:m
          % 逐個城市路徑選擇
         for j = 2:n
             tabu = Table(i,1:(j - 1));           % 已訪問的城市集合(禁忌表)
             allow_index = ~ismember(citys_index,tabu);
             allow = citys_index(allow_index);  % 待訪問的城市集合
             P = allow;
             % 計算城市間轉移概率
             for k = 1:length(allow)
                 P(k) = Tau(tabu(end),allow(k))^alpha * Eta(tabu(end),allow(k))^beta;
             end
             P = P/sum(P);
             % 輪盤賭法選擇下一個訪問城市
             Pc = cumsum(P);     
            target_index = find(Pc >= rand); 
            target = allow(target_index(1));
            Table(i,j) = target;
         end
      end
      % 計算各個螞蟻的路徑距離
      Length = zeros(m,1);
      for i = 1:m
          Route = Table(i,:);
          for j = 1:(n - 1)
              Length(i) = Length(i) + D(Route(j),Route(j + 1));
          end
          Length(i) = Length(i) + D(Route(n),Route(1));
      end
      % 計算最短路徑距離及平均距離
      if iter == 1
          [min_Length,min_index] = min(Length);
          Length_best(iter) = min_Length;  
          Length_ave(iter) = mean(Length);
          Route_best(iter,:) = Table(min_index,:);
      else
          [min_Length,min_index] = min(Length);
          Length_best(iter) = min(Length_best(iter - 1),min_Length);
          Length_ave(iter) = mean(Length);
          if Length_best(iter) == min_Length
              Route_best(iter,:) = Table(min_index,:);
          else
              Route_best(iter,:) = Route_best((iter-1),:);
          end
      end
      % 更新信息素
      Delta_Tau = zeros(n,n);
      % 逐個螞蟻計算
      for i = 1:m
          % 逐個城市計算
          for j = 1:(n - 1)
              Delta_Tau(Table(i,j),Table(i,j+1)) = Delta_Tau(Table(i,j),Table(i,j+1)) + Q/Length(i);
          end
          Delta_Tau(Table(i,n),Table(i,1)) = Delta_Tau(Table(i,n),Table(i,1)) + Q/Length(i);
      end
      Tau = (1-rho) * Tau + Delta_Tau;
    % 迭代次數加1,清空路徑記錄表
    iter = iter + 1;
    Table = zeros(m,n);
end

%% 結果顯示
[Shortest_Length,index] = min(Length_best);
Shortest_Route = Route_best(index,:);
disp(['最短距離:' num2str(Shortest_Length)]);
disp(['最短路徑:' num2str([Shortest_Route Shortest_Route(1)])]);

%% 繪圖
figure(1)
plot([citys(Shortest_Route,1);citys(Shortest_Route(1),1)],...
     [citys(Shortest_Route,2);citys(Shortest_Route(1),2)],'o-');
grid on
for i = 1:size(citys,1)
    text(citys(i,1),citys(i,2),['   ' num2str(i)]);
end
text(citys(Shortest_Route(1),1),citys(Shortest_Route(1),2),'       起點');
text(citys(Shortest_Route(end),1),citys(Shortest_Route(end),2),'       終點');
xlabel('城市位置橫座標')
ylabel('城市位置縱座標')
title(['蟻羣算法優化路徑(最短距離:' num2str(Shortest_Length) ')'])
figure(2)
plot(1:iter_max,Length_best,'b',1:iter_max,Length_ave,'r:')
legend('最短距離','平均距離')
xlabel('迭代次數')
ylabel('距離')
title('各代最短距離與平均距離對比')

最短距離:15601.9195
最短路徑:14  12  13  11  23  16   5   6   7   2   4   8   9  10   3  18  17  19  24  25  20  21  22  26  28  27  30  31  29   1  15  14
>> 

在這裏插入圖片描述在這裏插入圖片描述
轉載請標明出處,謝謝!。

如果感覺本文對您有幫助,請留下您的贊,您的支持是我堅持寫作最大的動力,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章