遺傳演算法求解旅行商(TSP)問題
1. TSP問題概述
TSP問題即旅行商問題,是數學領域的著名問題之一。假設有一個旅行商人要拜訪n個城市,他必須選擇所要走的路徑,路徑的限制是每個城市只能拜訪一次,而且最後要回到原來出發的城市。路徑的選擇目標是要使求得的路徑路程為所有路徑之中的最小值。
2. 基於遺傳演算法的TSP問題求解
(1)基因編碼
針對TSP問題,編碼規則通常採用實數(n進位制)編碼,即每個染色體僅從1到n的整數裡面取一個值,每個個體的長度為n,n為城市總數。即用一串基因編碼表示遍歷的城市順序,如:(2 3 4 5 1 7 9 8 6),表示九個城市中,先經過城市2,再經過城市3,以此類推。
(2)交叉運算元設計
採用部分匹配交叉(PMX)法:先隨機產生兩個交叉點,定義這兩點間的區域為匹配區域,並交換兩個父代的匹配區域。
父代A:872|130|9546
父代B:983|567|1420
TEMP A:872|567|9546
TEMP B:983|130|1420
對於TEMP A、TEMP B中匹配區域以外出現的數碼重複,要依據匹配區域內的位置逐一進行替換。匹配關係:1<------>5 3<----->6 7<---->0
子代A:802|567|9143
子代B:986|130|5427
(3)變異運算元設計
對於TSP問題,一般採用倒位變異法,即首先在父體中隨機選擇兩截斷點,然後將該兩點所夾的子串中的城市進行反序。
例如;
設原個體:(1 2 3 4 5 6 7 8 9)
隨機選擇兩點:(1 2|3 4 5 6| 7 8 9)
倒位後的個體:(1 2 |6 5 4 3|7 8 9)
(4)適應度函式
TSP問題的目標是路徑總長度為最短,可以用常數L除以某個體的路徑總長度作為該個體的是適應度函式。
3 . 演算法步驟
Step1:引數設定及種群初始化;
Step2;適應度評價;
Step3:輪盤賭選擇;
Step4:部分匹配交叉;
Step5:倒位變異;
Step6:適應度評價;
Step7:終止條件判斷,若未達到終止條件,則轉到step3;
Step8:輸出結果。
4.實現程式碼
%功能:基於遺傳演算法的TSP問題求解
function GA_for_TSP
clc;clear all;close all;
%初始化資料
city_num=30;
[city_distance,city_coordinate]=tsp_info(city_num);%距離矩陣和城市座標
pop=100;ger=800;pc=0.8;pm=0.2;history_best=inf;
for i=1:pop
individual(i,:)=randperm(city_num);%產生1~30之間的隨機排列數
end
[fitness,f]=evaluate_fitness(individual,city_distance);
it=1;
while it<=ger
disp(it)
new_individual=select(fitness,individual);%輪盤賭
new_individual=cross(new_individual,pc);
new_individual=mutation(new_individual,pm);
[fitness,f]=evaluate_fitness(new_individual,city_distance);
%取出最佳適應度的個體
[best_fitness,best_index]=max(fitness);
[worst_fitness,worst_index]=min(fitness);
best_f=f(best_index);
best_individual=new_individual(best_index,:);
new_individual(worst_index,:)=best_individual;
plot_dsp(city_coordinate,best_individual,best_f,it);
individual=new_individual;
if best_f<history_best
history_best=best_f;
history_best_individual=best_individual;
best_individual_last(it,:)=best_f;%???
else
best_individual_last(it,:)=history_best;
end
it=it+1;
end
disp(sprintf('最短路徑:%2.5f',history_best))
disp('路徑方案:')
disp(sprintf('%4d',history_best_individual));
%給每個城市標號
for i=1:size(city_coordinate,1)
text(city_coordinate(i,1),city_coordinate(i,2),num2str(i));
end
figure(2)
plot(best_individual_last,'r');hold on;
title('搜尋過程');
legend('最優路徑長度');
gtext(['(' num2str(it-1) ',' num2str(history_best) ')']);
%end
%******************Data子程式tsp_info***************************
function [city_distance,city_coordinate]=tsp_info(city_num)
%fid=fopen('city_coordinate.txt','r');
%city_coordinate=fscanf(fid,'%d',[50,2]);
%fclose(fid);
city_coordinate=[41,94;37,84;54,67;25,62;7,64;2,99;68,58;71,44;54,62;83,69;64,60;18,54;22,60;
83,46;91,38;25,38;24,42;58,69;71,71;74,78;87,76;18,40;13,40;82,7;62,32;58,35;45,21;41,26;44,35;4,50];
for i=1:city_num
for j=1:city_num
city_distance(i,j)=sqrt((city_coordinate(i,1)-city_coordinate(j,1))^2+(city_coordinate(i,2)-city_coordinate(j,2))^2);
end
end
%********************The end of tsp_info*****************
%********************適應度-->evaluate_fitness*************************
function [fitness,f]=evaluate_fitness(individual,city_distance)
[M,N]=size(individual);
for i=1:M
temp=0;
for j=1:N-1
temp=temp+city_distance(individual(i,j),individual(i,j+1));
end
f(i)=temp+city_distance(individual(i,N),individual(i,1));
fitness(i)=1000/f(i);
end
%*********************************the end*************************************
%*************************輪盤賭-->selcet***********************************
function new_individual=select(fitness,individual)
[m,n]=size(fitness');
for i=1:m
fit(i)=fitness(i)^20;
end
%fit=fitness.^20;
for i=1:m
sp(i)=fit(i)/sum(fit);
end
for i=2:m
sp(i)=sp(i-1)+sp(i);
end
for i=1:m
p=rand(1);
j=1;
while(p>sp(j))%找到sp(j)大於p的 j 值
j=j+1;
end
new_individual(i,:)=individual(j,:);
end
%***************************The End***********************************
%**************************交叉子程式*****************************
%功能:片段交叉
function new_individual=cross(new_individual,pc)
[M,N]=size(new_individual);
%先將順序打亂
for i=1:M
point=unidrnd(M-i+1);%產生隨機數
temp=new_individual(i,:);
new_individual(i,:)=new_individual(i+point-1,:);
new_individual(i+point-1,:)=temp;
end
for i=1:2:M-1
if pc>rand(1)
%產生兩個交叉位置
location_num1=round(rand(1)*(N-2))+1;
location_num2=round(rand(1)*(N-2))+1;
min_location=min([location_num1,location_num2]);
max_location=max([location_num1,location_num2]);
%交換相鄰兩行的片段
middle=new_individual(i,min_location+1:max_location);
new_individual(i,min_location+1:max_location)=new_individual(i+1,min_location+1:max_location);
new_individual(i+1,min_location+1:max_location)=middle;
%交叉完之後檢查個體序號是否有重複
for j=1:min_location%前半段
while find(new_individual(i,min_location+1:max_location)==new_individual(i,j))
num=find(new_individual(i,min_location+1:max_location)==new_individual(i,j));
new_num=new_individual(i+1,min_location+num);
new_individual(i,j)=new_num;
end
while find(new_individual(i+1,min_location+1:max_location)==new_individual(i+1,j))
num=find(new_individual(i+1,min_location+1:max_location)==new_individual(i+1,j));
new_num=new_individual(i,min_location+num);
new_individual(i+1,j)=new_num;
end
end
for j=max_location+1:N%後半段
while find(new_individual(i,1:max_location)==new_individual(i,j))
num=find(new_individual(i,1:max_location)==new_individual(i,j));
new_num=new_individual(i+1,num);
new_individual(i,j)=new_num;
end
while find(new_individual(i+1,1:max_location)==new_individual(i+1,j))
num=find(new_individual(i+1,1:max_location)==new_individual(i+1,j));
new_num=new_individual(i,num);
new_individual(i+1,j)=new_num;
end
end
end
end
%***************************The End***************************
%************************畫圖:plot_dsp*************************************
function plot_dsp(city_coordinate,best_individual,best_fitness,it)
[city_num,city]=size(city_coordinate);
for i=1:city_num-1
plot([city_coordinate(best_individual(i),1),city_coordinate(best_individual(i+1),1)],...
[city_coordinate(best_individual(i),2),city_coordinate(best_individual(i+1),2)],...
'm.-','LineWidth',2,'MarkerEdgeColor','k','MarkerFaceColor','b');
hold on;grid on;
end
plot([city_coordinate(best_individual(city_num),1),city_coordinate(best_individual(1),1)],...
[city_coordinate(best_individual(city_num),2),city_coordinate(best_individual(1),2)],...
'm.-','LineWidth',2,'MarkerEdgeColor','k','MarkerFaceColor','b');
title([num2str(city_num),'城市數量TSP問題']);grid on;
hold off;
pause(0.05);
%**************************the end************************************
%***************************變異子程式*******************************
%功能:變異子函式,片段倒序
function new_individual=mutation(new_individual,pm)
[M,N]=size(new_individual);%M:個體數,N:城市數
for i=1:N
if rand(1)<pm
location_num1=round(rand(1)*(N-2))+1;%產生1~N-1之間的隨機數
location_num2=round(rand(1)*(N-2))+1;
min_location=min([location_num1,location_num2]);%變異片段的最小序號
max_location=max([location_num1,location_num2]);%變異片段的最大序號
new_individual(i,min_location:max_location)=new_individual(i,max_location:-1:min_location);
end
end
%***************** The End ***************************