一、局部领域搜索

   又称爬山启发式算法,从当前的节点开始,和周围的邻居节点的值进行比较。如果当前节点是最大的,那么返回当前节点,作为最大值(山峰最高点);反之就用最高的邻居节点替换当前节点,从而实现向山峰的高处攀爬的目的。它是禁忌搜索的基础,TS算法是在其上改进而来。
       
优点:

        1、容易理解,容易实现,具有较强的通用性;

        2、局部开发能力强,收敛速度很快。

缺点:

        1、全局开发能力弱,只能搜索到局部最优解;

        2、搜索结果完全依赖于初始解和邻域的映射关系。


通过针对爬山法的分析,提出了TS搜索算法:

        改进1:接受劣解。

        改进2:引入禁忌表

        改进3:引入长期表和中期表。

 二、TS算法的特点:

       

1、基本思想——避免在搜索过程中的循环

    2、只进不退的原则,通过禁忌表实现    

    3、不以局部最优作为停止准则   

    4、邻域选优的规则模拟了人类的记忆功能

        TS算法构成要素:

       

    (1)编码方式
     

   将不相同的n件物品分为m组,可以用的编码:


   a、带分隔符的顺序编码

    以自然数1~n分别代表n件物品,n个数加上    

    m-1个分割符号混编在一起,随机排列。

    如:1-3-4-0-2-6-7-5-0-8-9

   b、自然数编码

   编码的每一位分别代表一件物品,而每一位的值代表该物品所在的分组。

    如:1-2-1-1-2-2-2-3-3

    (2)初始解的获取

   可以随机给出初始解,也可以事先使用其他启发式等算法给出一个较好的初始解。  

    (3)移动邻域
   移动是从当前解产生新解的途径,例如上述问题中用移动s产生新解s(x)
   从当前解可以进行的所有移动构成邻域,也可以理解为从当前解经过“一步”可以到达的区域。
    (4)禁忌表

   禁忌表的作用:防止搜索出现循环

   (1)记录前若干步走过的点、方向或目标值,禁止返回
   (2)表是动态更新的
   (3)表的长度称为Tabu-Size
  
  禁忌表的主要指标(两项指标

     禁忌对象:禁忌表中被禁的那些变化元素

     禁忌长度:禁忌的步数

  禁忌对象(三种变化)

     以状态本身或者状态的变化作为禁忌对象

     以状态分量以及分量的变化作为禁忌对象

     采用类似的等高线做法,以目标值变化作为禁忌对象

  禁忌长度:可以是一个固定的常数(T=c),也可以是动态变化的,可按照某种规则或公式在区间内变化。

  禁忌长度过短,一旦陷入局部最优点,出现循环无法跳出;
  禁忌长度过长,候选解全部被禁忌,造成计算时间较大,也可能造成计算无法继续下去。

    (5)渴望水平函数
   
   A(xs)一般为历史上曾经达到的最好目标值,若有C(s(x))<A(xs)S(x)是不受T表限制。即使s(x)∈T,仍可取        x=s(x)A(xs)称为渴望水平函数。
    (6)停止准则
    (1)给定最大迭代步数(最常用 )
    (2)设定某个对象的最大禁忌频率。
    (3)设定适配值的偏离阈值。
 
  TS算法流程图:
  
 三、 TS举例:七层材料问题

  由7层不同的绝缘材料构成的一种绝缘体,应如何排列顺序,可获得最好的绝缘性能。

  

   编码方式:顺序编码

       初始编码:2-5-7-3-4-6-1

       目标值:极大化目标值。

  邻域移动:两两交换

  TabuSize3  NG5

  



    

  


四、TS算法解决TSP问题:

%%一个旅行商人要拜访全国31个省会城市,且每个城市只能拜访一次,求所有路径之中的最小值

%%%禁忌搜索算法求解TSP问题%%%%%%%%%%%%%%%%%%%%%
function [BestShortcut,theMinDistance]=TabuSearch
clear;
clc;
Clist=[1304 2312;3639 1315;4177 2244;3712 1399;3488 1535;3326 1556;3238 1229;...
    4196 1044;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 2376;3394 2643;3439 3201;2935 3240;3140 3550;...
    2545 2357;2778 2826;2370 2975];%全国31个省会城市坐标

CityNum=size(Clist,1);%TSP问题的规模,即城市数目
dislist=zeros(CityNum); 
for i=1:CityNum
    for j=1:CityNum
        dislist(i,j)=((Clist(i,1)-Clist(j,1))^2+(Clist(i,2)-Clist(j,2))^2)^0.5;       
    end
end
TabuList=zeros(CityNum);                      % (tabu list)
TabuLength=round((CityNum*(CityNum-1)/2)^0.5);%禁忌表长度(tabu length)
Candidates=200;                               %候选集的个数 (全部领域解个数)
CandidateNum=zeros(Candidates,CityNum);       %候选解集合
S0=randperm(CityNum);                         %随机产生初始解
BSF=S0;                                       %best so far;
BestL=Inf;                                    %当前最佳解距离
p=1;                                         %记录迭代次数
StopL=2000;                                  %最大迭代次数

figure(1);
stop = uicontrol('style','toggle','string'...
,'stop','background','white');
tic;                                         %用来保存当前时间
%%%%%%%%%%%%%%%%%%%%%%禁忌搜索循环%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
while p<StopL
    if Candidates>CityNum*(CityNum-1)/2
        disp('候选解个数不大于n*(n-1)/2!');
        break;
    end
    ALong(p)=Fun(dislist,S0);      %当前解适配值
    
    i=1;
    A=zeros(Candidates,2);          % 解中交换的城市矩阵

    %以下while的 是生成随机的200 X 2  的矩阵矩阵A。每一个元素都是在1-31之间的
    while i<=Candidates        
        M=CityNum*rand(1,2);
        M=ceil(M);
        if M(1)~=M(2)
            A(i,1)=max(M(1),M(2));
            A(i,2)=min(M(1),M(2));
                if i==1
                isa=0;
            else
                for j=1:i-1
                    if A(i,1)==A(j,1) && A(i,2)==A(j,2)
                        isa=1;
                        break;
                    else
                        isa=0;
                    end
                end
            end 
            if ~isa
               i=i+1;
            else 
            end            
        else 
        end
    end
    %%%%%%%%产生领域解%%%%%%%%%%%%%%%%%%%%%%%
    BestCandidateNum=100;%保留前BestCandidateNum个最好候选解
    BestCandidate=Inf*ones(BestCandidateNum,4);
    F=zeros(1,Candidates);
    
    %这相当于是产生一个S0的邻域...
    for i=1:Candidates
        CandidateNum(i,:)=S0;  %候选解集合。
        CandidateNum(i,[A(i,2),A(i,1)])=S0([A(i,1),A(i,2)]);
        F(i)=Fun(dislist,CandidateNum(i,:));
        if i<=BestCandidateNum
            BestCandidate(i,2)=F(i);
            BestCandidate(i,1)=i;
            BestCandidate(i,3)=S0(A(i,1));
            BestCandidate(i,4)=S0(A(i,2));   
        else
            for j=1:BestCandidateNum
                if F(i)<BestCandidate(j,2)
                    BestCandidate(j,2)=F(i);
                    BestCandidate(j,1)=i;
                    BestCandidate(j,3)=S0(A(i,1));
                    BestCandidate(j,4)=S0(A(i,2));
                    break;
                end            
            end
        end
    end
    %对BestCandidate 
    [JL,Index]=sort(BestCandidate(:,2)); 
    SBest=BestCandidate(Index,:);
    BestCandidate=SBest;
    %%%%%%%%%%%%%%%%%%%%%%%藐视准则%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      if BestCandidate(1,2)<BestL
        BestL=BestCandidate(1,2);
        S0=CandidateNum(BestCandidate(1,1),:);        
        BSF=S0;
        for m=1:CityNum
            for n=1:CityNum
                if TabuList(m,n)~=0
                    TabuList(m,n)=TabuList(m,n)-1;      % 更新禁忌表
                end
            end
        end
        TabuList(BestCandidate(1,3),BestCandidate(1,4))=TabuLength;   % 更新禁忌表
    else  
        
for i=1:BestCandidateNum
            if  TabuList(BestCandidate(i,3),BestCandidate(i,4))==0
                S0=CandidateNum(BestCandidate(i,1),:);                
            for m=1:CityNum
                for n=1:CityNum
                    if TabuList(m,n)~=0
                        TabuList(m,n)=TabuList(m,n)-1;                % 更新禁忌表
                    end
                end
            end        
            TabuList(BestCandidate(i,3),BestCandidate(i,4))=TabuLength;       % 更新禁忌表
            break;
            end
        end
      end
    
      
   
    ArrBestL(p)=BestL; 
    
    
    for i=1:CityNum-1
        plot([Clist(BSF(i),1),Clist(BSF(i+1),1)],[Clist(BSF(i),2),Clist(BSF(i+1),2)],'bo-');
        hold on;
    end
    plot([Clist(BSF(CityNum),1),Clist(BSF(1),1)],[Clist(BSF(CityNum),2),Clist(BSF(1),2)],'ro-');
    title(['迭代次数:',int2str(p),' 优化最短距离:',num2str(BestL)]);
    hold off;
    pause(0.005);
    if get(stop,'value')==1
        break;
    end
    %存储中间结果为图片
    if (p==1||p==5||p==10||p==20||p==60||p==150||p==400||p==800||p==1500||p==2000)
        filename=num2str(p);
        fileformat='jpg';
        saveas(gcf,filename,fileformat);
    end 
    p=p+1;                                                          %迭代次数加1
end
toc;                                         %用来保存完成时间
BestShortcut=BSF;                            %最佳路线
theMinDistance=BestL;                        %最佳路线长度
set(stop,'style','pushbutton','string','close', 'callback','close(gcf)');

figure(2);
plot(ArrBestL,'b');
xlabel('迭代次数');
ylabel('目标函数值');
title('适应度进化曲线');
grid;
hold on;


%%figure(3)
%%plot(toc-tic,'b');
%%grid;
%%title('运行时间');
%%legend('Best So Far','当前解');




%%%%%适配值函数%%%%%%%%%%%%%%%%%%%%%
function F=Fun(dislist,s)   
DistanV=0;
n=size(s,2);
for i=1:(n-1)
    DistanV=DistanV+dislist(s(i),s(i+1));
end
    DistanV=DistanV+dislist(s(n),s(1));      
F=DistanV;



Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐