TSP问题(Travelling Salesman Problem)又译为旅行推销员问题、货郎担问题,即假设有一个旅行商人要拜访n个城市,从某个城市出发,每个城市只能访问一次且最后回到出发城市,问该推销员应如何选择路线,才能使总的行程最短?
使用动态规划解决该问题的策略为:
易知从哪个城市出发其最短路径都是一样的,故假设从城市1出发。假设已经经过了几个城市,我们需要记录此时位于的城市,以及未访问的城市的集合。\ 以dp[{V}][init]表示从init点开始,要经过集合V中所有点的距离。dis[init][i]表示城市init到城市i的距离。\ 其状态转移方程为dp[{V}][init]=min(dp[{V}][init], dp[{V-i}][i]+dis[init][i])。即假设处于城市init,欲前往下一个城市i,如果在城市i的状态dp[{V-i}][i]加上城市init到城市i的距离小于当前最小值,则前往城市i。\ 我们怎么存储未访问的城市的集合?一个方法是以二进制01表示该城市是否被访问过,如s=111110,城市1对应的位为0,其他城市对应的位为1,则表示城市6到城市2都还未访问,城市1已访问过。例如在出发点1时,要判断城市2是否访问过,若s&(1<<1)为1则表示城市2未被访问过,若去城市2,则集合V变为s&(\~(1<<1))。\ 以数组path[s][init]记录在城市init,未访问城市集合为s时,下一个城市的最优选择,以存储最优路径。
``` %蚁群算法求解TSP问题的matlab程序 clear all close all clc % 程序运行计时开始 t0 = clock; %初始化蚁群 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个省会坐标 Ncmax=100;%最大循环次数,即算法迭代的次数,亦即蚂蚁出动的拨数(每拨蚂蚁的数量当然都是m) alpha=1;%蚂蚁在运动过程中所积累信息(即信息素)在蚂蚁选择路径时的相对重要程度,alpha过大时,算法迭代到一定代数后将出现停 beta=5;%启发式因子在蚂蚁选择路径时的相对重要程度 rho=0.2;%0 ph=1000; min ph=0; pheromone=maxph.*ones(n,n);%信息素矩阵 tabu list=zeros(m,n);%禁忌表,记录蚂蚁已经走过的城市,蚂蚁在本次循环中不能再经过这些城市。当本次循环结束后,禁忌表被用来 repeat=0; scale=1; Nc=0;%循环次数计数器 routhbest=zeros(Nc max,n);%各次循环的最短路径 lengthbest=ones(Nc max,1);%各次循环最短路径的长度 lengthaverage=ones(Nc_max,1);%各次循环所有路径的平均长度
while Nc
%将m只蚂蚁放在n个城市上
rand_position=[];
for i=1:ceil(m/n)
rand_position=[rand_position,randperm(n)];
end
tabu_list(:,1)=(rand_position(1:m))';%将蚂蚁放在城市上之后的禁忌表,第i行表示第i只蚂蚁,第i行第一列元素表示第i只蚂蚁
%m只蚂蚁按概率函数选择下一座城市,在本次循环中完成各自的周游
for j=2:n
for i=1:m
city_visited=tabu_list(i,1:(j-1));%已访问的城市
city_remained=zeros(1,(n-j+1));%待访问的城市
probability=city_remained;%待访问城市的访问概率
cr=1;
for k=1:n%for循环用于求待访问的城市。比如如果城市个数是5,而已访问的城市city_visited=[2 4],则经过此for循环后
if length(find(city_visited==k))==0
city_remained(cr)=k;
cr=cr+1;
end
end
%状态转移规则****************************************
q0=0.5;
if rand>q0
for k=1:length(city_remained)
probability(k)=(pheromone(city_visited(end),city_remained(k)))^alpha*(eta(city_visited(end),city_remained(k)))^beta;
position=find(probability==max(probability));
to_visit=city_remained(position(1));
end
else
for k=1:length(city_remained)
probability(k)=(pheromone(city_visited(end),city_remained(k)))^alpha*(eta(city_visited(end),city_remained(k)))^beta;
end
probability=probability/sum(probability);
pcum=cumsum(probability);
select=find(pcum>=rand);
to_visit=city_remained(select(1));
end
tabu_list(i,j)=to_visit;
%**************************************************************
end
end
if Nc>0
tabu_list(1,:)=routh_best(Nc,:);%将上一代的最优路径(最优解)保留下来,保证上一代中的最适应个体的信息不会丢失
end
%记录本次循环的最佳路线
total_length=zeros(m,1);%m只蚂蚁在本次循环中分别所走过的路径长度
for i=1:m
r=tabu_list(i,:);%取出第i只蚂蚁在本次循环中所走的路径
for j=1:(n-1)
total_length(i)=total_length(i)+D(r(j),r(j+1));%第i只蚂蚁本次循环中从起点城市到终点城市所走过的路径长度
end
total_length(i)=total_length(i)+D(r(1),r(n));%最终得到第i只蚂蚁在本次循环中所走过的路径长度
end
length_best(Nc+1)=min(total_length); %把m只蚂蚁在本次循环中所走路径长度的最小值作为本次循环中最短路径的长度
position1=find(total_length==length_best(Nc+1));%找到最短路径的位置,即最短路径是第几只蚂蚁或哪几只蚂蚁走出来的
routh_best(Nc+1,:)=tabu_list(position1(1),:);%把第一个走出最短路径的蚂蚁在本次循环中所走的路径作为本次循环中的最优路径
length_average(Nc+1)=mean(total_length);%计算本次循环中m只蚂蚁所走路径的平均长度
f_best=length_best(1)
if f_best>length_best(Nc+1)
f_best=length_best(Nc+1)
end
%更新信息素
delta_pheromone=zeros(n,n);
for j=1:n-1
delta_pheromone(tabu_list(position(1),j),tabu_list(position(1),j+1))=delta_pheromone(tabu_list(position(1),j),tabu_list(position(1),j+1))+1/log(length_best(Nc+1));
delta_pheromone(tabu_list(position(1),n),tabu_list(position(1),1))=delta_pheromone(tabu_list(position(1),n),tabu_list(position(1),1))+1/log(length_best(Nc+1));
if mod(Nc,5)==0
delta_pheromone(tabu_list(position(1),j),tabu_list(position(1),j+1))=delta_pheromone(tabu_list(position(1),j),tabu_list(position(1),j+1))+1/log(f_best);
delta_pheromone(tabu_list(position(1),n),tabu_list(position(1),1))=delta_pheromone(tabu_list(position(1),n),tabu_list(position(1),1))+1/log(f_best);
end
end%至此把m只蚂蚁在本次循环中在所有路径上释放的信息素已经累加上去 %t=sigmf(Nc,[-0.01 Ncmax/2]) pheromone=0.6.*pheromone+deltapheromone; maxph=max(pheromone(1,:)); minph=maxph/(2*n); for i=1:n for j=1:n if(pheromone(i,j)>maxph) pheromone(i,j)=maxph; end if(pheromone(i,j) ph) pheromone(i,j)=min ph;
end end end tabulist=zeros(m,n); Nc=Nc+1 end
%输出结果,绘制图形 position=find(lengthbest==min(lengthbest)); shortestpath=routhbest(position(1),:) shortestlength=lengthbest(position(1)) %绘制最短路径 figure(1) set(gcf,'Name','Ant Colony Optimization——Figure of shortestpath','Color','r') N=length(shortestpath); scatter(C(:,1),C(:,2),10,'filled'); hold on plot([C(shortestpath(1),1),C(shortestpath(N),1)],[C(shortestpath(1),2),C(shortestpath(N),2)]) set(gca,'Color','g') hold on for i=2:N plot([C(shortestpath(i-1),1),C(shortestpath(i),1)],[C(shortestpath(i-1),2),C(shortestpath(i),2)]) hold on end %绘制每次循环最短路径长度和平均路径长度 figure(2) set(gcf,'Name','Ant Colony Optimization——Figure of lengthbest and lengthaverage','Color','r') plot(lengthbest,'r') set(gca,'Color','g') hold on plot(lengthaverage,'k') ```