基於蟻群算法的10個城市TSP問題的最短路徑研究
1 蟻群算法
1.1 蟻群算法的流程步驟
這里以TSP問題為例,算法設計的流程如下:
步驟1:對相關參數進行初始化,包括蟻群規模、信息素因子、啟發函數因子、信息素揮發因子、信息素常數、最大迭代次數等,以及將數據讀入程序,並進行預處理:比如將城市的坐標信息轉換為城市間的距離矩陣。
步驟2:隨機將螞蟻放於不同出發點,對每個螞蟻計算其下個訪問城市,直到有螞蟻訪問完所有城市。
步驟3:計算各螞蟻經過的路徑長度 ,記錄當前迭代次數最優解,同時對路徑上的信息素濃度進行更新。
步驟4:判斷是否達到最大迭代次數,若否,返回步驟2;是,結束程序。
步驟5:輸出結果,並根據需要輸出尋優過程中的相關指標,如運行時間、收斂迭代次數等。
要用到的符號說明:
mm:整個螞蟻群體中螞蟻數量;nn:城市的數量; :城市i與城市j的距離 ; :t時刻城市i和城市j連接路徑上的信息素; :t時刻螞蟻k從城市i轉移到城市j的概率。
初始時刻螞蟻被放在不同的城市,且各城市路徑上的信息素濃度為0。
由於蟻群算法涉及到的參數蠻多的,且這些參數的選擇對程序又都有一定的影響,所以選擇合適的參數組合很重要。蟻群算法有個特點就是在尋優的過程中,帶有一定的隨機性,這種隨機性主要體現在出發點的選擇上。蟻群算法正是通過這個初始點的選擇將全局尋優慢慢轉化為局部尋優的。參數設定的關鍵就在於在“全局”和“局部”之間建立一個平衡點。
1.2 蟻群算法的關鍵參數
在蟻群算法的發展中,關鍵參數的設定有一定的准則,一般來講遵循以下幾條:
盡可能在全局上搜索最優解,保證解的最優性;
算法盡快收斂,以節省尋優時間;
盡量反應客觀存在的規律,以保證這類仿生算法的真實性。
螞蟻數量:
設M表示城市數量,m表示螞蟻數量。m的數量很重要,因為m過大時,會導致搜索過的路徑上信息素變化趨於平均,這樣就不好找出好的路徑了;m過小時,易使未被搜索到的路徑信息素減小到0,這樣可能會出現早熟,沒找到全局最優解。一般上,在時間等資源條件緊迫的情況下,螞蟻數設定為城市數的1.5倍較穩妥。
信息素因子:
信息素因子反映了螞蟻在移動過程中所積累的信息量在指導蟻群搜索中的相對重要程度,其值過大,螞蟻選擇以前走過的路徑概率大,搜索隨機性減弱;值過小,等同於貪婪算法,使搜索過早陷入局部最優。實驗發現,信息素因子選擇[1,4]區間,性能較好。
啟發函數因子:
啟發函數因子反映了啟發式信息在指導蟻群搜索過程中的相對重要程度,其大小反映的是蟻群尋優過程中先驗性和確定性因素的作用強度。過大時,雖然收斂速度會加快,但容易陷入局部最優;過小時,容易陷入隨機搜索,找不到最優解。實驗研究發現,當啟發函數因子為[3,4.5]時,綜合求解性能較好。
信息素揮發因子:
信息素揮發因子表示信息素的消失水平,它的大小直接關系到蟻群算法的全局搜索能力和收斂速度。實驗發現,當屬於[0.2,0.5]時,綜合性能較好。
信息素常數:
這個參數為信息素強度,表示螞蟻循環一周時釋放在路徑上的信息素總量,其作用是為了充分利用有向圖上的全局信息反饋量,使算法在正反饋機制作用下以合理的演化速度搜索到全局最優解。值越大,螞蟻在已遍歷路徑上的信息素積累越快,有助於快速收斂。實驗發現,當值屬於[10,1000]時,綜合性能較好。
最大迭代次數:
最大迭代次數值過小,可能導致算法還沒收斂就已結束;過大則會導致資源浪費。一般最大迭代次數可以取100到500次。一般來講,建議先取200,然后根據執行程序查看算法收斂的軌跡來修改取值。
組合參數設計策略:
通常可以按照以下策略來進行參數組合設定:
- 確定螞蟻數目,螞蟻數目與城市規模之比約為1.5;
- 參數粗調,即調整取值范圍較大的α,β及Qα,β及Q;
- 參數微調,即調整取值范圍較小的ρ。
2 實驗結果
2.1 實驗代碼
(1)ACATSP.m
function [R_best,L_best,L_ave,Shortest_Route,Shortest_Length]=ACATSP(C,NC_max,m,Alpha,Beta,Rho,Q)
%%-------------------------------------------------------------------------
%% 主要符號說明
%% C n個城市的坐標,n×2的矩陣
%% NC_max 最大迭代次數
%% m 螞蟻個數
%% Alpha 表征信息素重要程度的參數
%% Beta 表征啟發式因子重要程度的參數
%% Rho 信息素蒸發系數
%% Q 信息素增加強度系數
%% R_best 各代最佳路線
%% L_best 各代最佳路線的長度
%%=========================================================================
%%第一步:變量初始化
n=size(C,1);%n表示問題的規模(城市個數)
D=zeros(n,n);%D表示完全圖的賦權鄰接矩陣
for i=1:n
for j=1:n
if i~=j
D(i,j)=((C(i,1)-C(j,1))^2+(C(i,2)-C(j,2))^2)^0.5;
else
D(i,j)=eps; %i=j時不計算,應該為0,但后面的啟發因子要取倒數,用eps(浮點相對精度)表示
end
D(j,i)=D(i,j); %對稱矩陣
end
end
%{
1.C就是城市坐標
x y
城市1 0 120
城市2 120 0
城市n 100 230
2.運行后這里D變成了一個n*n的矩陣,每個元素代表兩個城市之間的距離,比如當城市數目為3時:
D= 城市1 城市2 城市3
城市1 0 120 100
城市2 120 0 230
城市3 100 230 0
這里D是個對角線為0的對稱矩陣,因為城市1,2間距離等於城市2,1的距離,城市n與n距離設置為0
%}
Eta=1./D; %Eta為啟發因子矩陣,這里設為距離的倒數
Tau=ones(n,n); %Tau為信息素矩陣
Tabu=zeros(m,n); %存儲並記錄路徑的生成,禁忌表
NC=1; %迭代計數器,記錄迭代次數
R_best=zeros(NC_max,n); %各代最佳路線
L_best=inf.*ones(NC_max,1); %各代最佳路線的長度
L_ave=zeros(NC_max,1); %各代路線的平均長度
while NC<=NC_max %停止條件之一:達到最大迭代次數,停止
%%第二步:將m只螞蟻放到n個城市上
Randpos=[]; %隨機存取
for i=1:(ceil(m/n))
Randpos=[Randpos,randperm(n)];
end
Tabu(:,1)=(Randpos(1,1:m))';
%{
1.ceil(m/n)
假如有 10只螞蟻,3個城市,ceil(m/n)=ceil(10/3)=4,需要安排四次,才能把這十只螞蟻全部放到到三個城市,
每次都在行向量Randpos加入如新的元素,randperm(3)表示就是1 3 2,或者3 1 2這種隨機組合,4次循環之后,
那么Randpos =
2 3 1 1 2 3 3 1 2 3 2 1
2.Tabu(:,1)=(Randpos(1,1:m))'
總共m螞蟻,只這里m為10,Tabu(:,1)表示Tabu第一行就是初始10只螞蟻被隨機分到所三個城市中的一個
Tabu =
2
3
1
1
2
3
3
1
2
3
這里只取m=10個數,因為Tabu第一列表示m只螞蟻初始的時候隨機被分在的城市,比如第一個2代表,第一只螞蟻
最開始放在了城市2,以此類推
%}
%%第三步: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; %這時記錄沒有訪問的城市到J中
Jc=Jc+1; %訪問的城市個數自加1
end
end
%{
1.visited=Tabu(i,1:(j-1)); 向量visited記錄已訪問的城市,比如第一次Tabu中第一行第一個的城市2
2.J=zeros(1,(n-j+1)) 向量J記錄待訪問的城市,已結訪問城市2,還沒訪問1和3城市放入J向量中
3.if length(find(visited==k))==0
判斷語句,find()語句找到visited中等於k的元素在數組visited中的位置,例如數組a=[1 2 3 4 5 2],
find(a==2)=[2,6],find(a==6)=[],則
length(find(a==6))=0
length()==0判斷length()是否為零
如果為零就是visited中沒有k元素,即沒有訪問過k城市。
這時記錄沒有訪問的城市到J中。
%}
%下面計算待選城市的概率分布
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); %若計算的概率大於原來的就選擇這條路線%要選擇其中總概率大於等於某一個隨機數,找到大於等於這個隨機數的城市的在J中的位置
to_visit=J(Select(1)); %提取這些城市的編號到to_visit中
Tabu(i,j)=to_visit;
end
end
%{
1. %visited(end)表示螞蟻現在所在城市編號,J(k)表示下一步要訪問的城市編號
2.P=P/(sum(P));把各個路徑概率統一到和為1
3.Pcum=cumsum(P); cumsum,元素累加即求和,比如P=[0.1 0.5 0.4],cumsum(P)= [0.1000 0.6000 1.0000]
有一點要特別說明,用到cumsum(P),螞蟻要選擇的下一個城市不是按最大概率,就是要用到輪盤法則,不然影響全局收縮能力,
所以用到累積函數,Pcum=cumsum(P)
4.Select=find(Pcum>=rand); to_visit=J(Select(1))
輪盤法則,Select(1),1保證可以選到最大概率的城市,具體自己可以用matlab試一下:
p=[0.1 0.6 0.3] 中間那個城市概率最大
此時Pcum=[0.1 0.7 1], Select =[2 3]; Select(1)=2,中間那個城市概率最大
%}
if NC>=2
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
%{
1.L=zeros(m,1) 記錄本次迭代最佳路線的長度,每個螞蟻都有自己走過的長度記錄在向量L中
%}
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; %迭代繼續
%{
1.R_best(NC,:)=Tabu(pos(1),:):找到路徑最短的那條螞蟻所在的城市先后順序,pos(1)中1表示萬一有長度一樣的兩條螞蟻,那就選第一個
%}
%%第五步:更新信息素
Delta_Tau=zeros(n,n); %開始時信息素為n*n的0矩陣
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
%{
1.R_best(NC,:)=Tabu(pos(1),:):找到路徑最短的那條螞蟻所在的城市先后順序,pos(1)中1表示萬一有長度一樣的兩條螞蟻,那就選第一個
%}
%%第七步:輸出結果
Pos=find(L_best==min(L_best)); %找到最佳路徑(非0為真)
Shortest_Route=R_best(Pos(1),:); %最大迭代次數后最佳路徑
Shortest_Length=L_best(Pos(1)); %最大迭代次數后最短距離
subplot(1,2,1) %繪制第一個子圖形
DrawRoute(C,Shortest_Route) %畫路線圖的子函數
subplot(1,2,2) %繪制第二個子圖形
plot(L_best)
hold on %保持圖形
plot(L_ave,'r')
title('平均距離和最短距離') %標題
(2) DrawRoute.m
function DrawRoute(C,R)
%%=========================================================================
%% DrawRoute.m
%% 畫路線圖的子函數
%%-------------------------------------------------------------------------
%% C Coordinate 節點坐標,由一個N×2的矩陣存儲
%% R Route 路線
%%=========================================================================
N=length(R);
scatter(C(:,1),C(:,2));
hold on
plot([C(R(1),1),C(R(N),1)],[C(R(1),2),C(R(N),2)],'r')
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)],'r')
hold on
end
title('旅行商問題優化結果 ')
2.2 實驗繪圖
命令行窗口輸入以下參數:
c=[1,2;70,90;80,60;10,100;800,200;800,100;90,80;200,600;230,4;500,90];
nc=100;
m=18;
a=1;
b=5;
p=0.5;
q=1;
ACATSP(c,nc,m,a,b,p,q);
得到下圖: