因为课程需要接触蚁群算法,开始着手在网上找一些资料,虽说网上的资料中已经有注释了,但是对我这个之前没有接触过蚁群算法的新手来说还是不太清楚,所以就将自己对蚁群算法程序的理解附上注释发上来,因为是自己的理解所以肯定会有不正确的地方,希望能够给大家一些不同的思考角度,也希望大家能够提出来自己的理解共同交流。
m=50; % m 蚂蚁个数
Alpha = 1; % 信息素重要程度的参数
Beta = 5; % 启发式因子重要程度的参数
Rho = 0.1; % 信息素蒸发系数
NC_max = 200; % 最大迭代次数
Q = 100; % 信息素增加强度系数
filename = 'C.txt';
C = load(filename); % 加载城市坐标文件
% R_best 各代最佳路线
% L_best 各代最佳路线的长度
%% 第一步,变量初始化
n = size(C,1); % n表示问题的规模,size函数获取向量第一列的行数
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; % 计算任意两个城市i和j之间的距离,存放在矩阵D中
else
D(i,j) = eps; %i=j时,赋一个很小的值,因为后面启发因子计算要取距离的导数
end
D(j,i) = D(i,j); % 这句是不是可以不用,因为通过上面计算出来的已经是一个对称矩阵了
end
end
Eta = 1./D; % 启发因子,设为距离的倒数
Tau = ones(n,n); % 信息素矩阵,每条路径初始化为1
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 % 开始迭代,总共迭代NC_max次停止
% 在这个while中完成每次NC次蚂蚁寻找城市的迭代
%% 第二步,将m只蚂蚁放到n个城市上
Randpos = []; %随即存取
for i=1:(ceil(m/n)) % ceil朝正无穷方向取整
Randpos = [Randpos,randperm(n)]; % randperm函数将1~n序列随机打乱返回
% 对ceil(m/n)的一些理解,m只蚂蚁放到n个城市上,蚂蚁多城市少,每个城市一只蚂蚁
%
end
Tabu(:,1) = (Randpos(1,1:m))'; % Randpos生成的本来是一个行向量,通过转置变为列向量,再取第一列前m个元素赋给Tabu
% 作为蚂蚁出发时的城市
%% 第三步,m只蚂蚁按概率函数选择下一座城市
for j=2:n %出发时所在的城市不算
for i=1:m
visited = Tabu(i,1:(j-1)); % Tabu中的第i行代表第i只蚂蚁已经访问过的城市,同时也代表走过的路径
% 记录到visited中
J = zeros(1,(n-j+1)); % 剩下n-j+1个没访问的城市存在J中,行向量
P = J; % 对应未访问城市的访问概率
Jc = 1; % 城市在J中的标号
%遍历所有城市,找出所有没有被访问过的城市
for k=1:n
if length(find(visited==k))==0 %如果城市k没有被访问过
J(Jc)=k; %将k记录到待访问城市列表中
Jc = Jc+1;
end
end
% 计算待访问城市的概率分布
for k=1:length(J) %遍历所有未访问的城市
P(k)=(Tau(visited(end),J(k))^Alpha)*(Eta(visited(end),J(k))^Beta);
% Tau(visited(end),J(k))为从蚂蚁当前所在城市到下一个未访问城市之间路径上的信息素浓度
end
P = P/(sum(P));
% 按概率原则选取下一个城市
Pcum = cumsum(P); %使用cumsum(P)不是用概率最大,而是用轮盘法则
Select = find(Pcum>=rand);
to_visit = J(Select(1));
Tabu(i,j) = to_visit; % 第i只蚂蚁访问的第j个城市记录在Tabu(i,j)中
end
end
if NC>=2
Tabu(1,:)=R_best(NC-1,:); % Tabu的第一行中保存着蚂蚁走过的最佳路径
% 将上一次迭代的最佳路径保存在Tabu中,与本次迭代的路径进行比较,这样可以找到全局最佳路径
end
%第四步,记录本次迭代最佳路径
L = zeros(m,1); %使用列向量L来保存m只蚂蚁走过路径的长度
for i=1:m % 遍历每只蚂蚁
R=Tabu(i,:); %将第i只蚂蚁的最佳路径放在行向量R中
for j=1:(n-1) % n城市之间有n-1条路径
L(i) = L(i)+D(R(j),R(j+1)); %R(j)和R(j+1)分别表示第j个和第j+1个城市,D(R(j),R(j+1))表示第j个城市和第j+1个城市之间的距离
end
L(i) = L(i)+D(R(1),R(n)); %一轮走下来的路径长度再加上第一个城市和第n个城市之间的距离,这样就形成一个封闭的图形,因为题目要求要回到出发点
end
L_best(NC) = min(L); % 在所有蚂蚁走过的路径中,选择最短的一条路径作为本次迭代最佳路径,并将其长度保存在L_best(NC)中,这里L是用来判断最佳路径的
Pos = find(L==L_best(NC)); % 找到L中最短路径所在的位置,也就是走出最短路径的那只蚂蚁
R_best(NC,:) = Tabu(pos(1),:); % 将走出最佳路径的那只蚂蚁的路径保存在R_best中,也就是说R_best中记录了本次迭代的最佳路径
L_ave(NC) = mean(L); % 本次迭代后的平均距离
NC = NC+1; % 进入下一次迭代
% 第五步,更新信息素
Delta_Tau = zeros(n,n); %建立信息素矩阵
for i=1:m % m只蚂蚁
for j=1:(n-1) % 每只蚂蚁n-1条路径
Delta_Tau(Tabu(i,j),Tabu(i,j+1))=Delta_Tau(Tabu(i,j),Tabu(i,j+1)+Q/L(i)); % Tabu(i,j)为第i只蚂蚁爬过的第j个城市,Tabu(i,j+1)为第i只蚂蚁爬过的第j+1个城市
% Delta_Tau(Tabu(i,j),Tabu(i,j+1))为第i只蚂蚁路径上相邻的两个城市j和j+1之间的信息素浓度增量
% 本次迭代中两个城市j和j+1之间的信息素浓度增量等于上一次迭代中这段路径上的浓度增量+常数
end
Delta_Tau(Tabu(i,n),Tabu(i,1)) = Delta_Tau(Tabu(i,n),Tabu(i,1))+Q/L(i); % 第i只蚂蚁爬过的整条路径上的信息素增量
end
Tau = (1-Rho).*Tau+Delta_Tau; %信息素挥发后,剩下的信息素,这是对所有蚂蚁走过的路径进行更新的
Tabu = zeros(m,n); %禁忌表清零,代表新一次迭代开始,直到达到最大迭代次数
end
% 输出结果
Pos = find(L_best==min(L_best)); % 找到长度最短的路径的位置,即最佳路径的位置
Shortest_Route = R_best(Pos(1),:); %最佳路径
Shortest_Length = L_best(Pos(1)); % 最佳路径对应的长度
按概率原则选取下一个城市使用的轮盘法,可以参考另一篇博文:
/*****************************/
C.txt 文件
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
/*****************************/