1. 程式人生 > >遺傳演算法求解旅行商(TSP)問題

遺傳演算法求解旅行商(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 ***************************