禁忌搜索算法(tabu search)解决TSP及其Matlab代码

1、算法简介

禁忌搜索算法TS(Tabu search),顾名思义核心在于“禁忌”,简单来说就是在某一个过程中把一些不太好的操作给禁止了,直到搜索到一个“最优秀”的。它是在1986年由美国Fred Glover教授提出的,主要是为了提高寻优过程中的全面搜索的能力。

 

 

禁忌搜索算法通过模拟人类智能的记忆特点,引入存储结构和相应的禁忌准则来避免迂回循环,通过特赦准则来释放禁忌表中较优的个体,进而保证多样性的搜索来尽可能达到问题的最优解。

2、算法核心概念

禁忌表(TabuList):是用来存放禁忌对象的表。它是TS算法的核心,禁忌表的值在每一次迭代过程中都会完成一次更新。禁忌对象可以是TSP中的路径长度、城市顺序等等。

禁忌长度(TabuLength):禁忌表中存放的数值即为禁忌长度,它规定了禁忌对象的生存时间,一旦达到其禁忌长度,则会被解除禁忌状态。禁忌长度的选取有静态和动态选取两种方法,静态选取会事先固定禁忌长度,而动态选取则会根据迭代过程而发生变化。

特赦准则:是在搜索过程中,发现有解比当前最优解更优时执行替换最优解的操作,或者在搜索过程中全部候选解都在“禁忌”状态,能够释放特定解的操作。

领域解:在初始解的基础上,按照一定的方向对初始解进行移动所形成的新解,称为领域解。不重复的移动次数称为领域的规模。

候选解:候选解就是领域解中较为优秀的一部分解。若候选解所选的规模较小,算法则会过早收敛,造成局部最优解的情况,若候选解所选规模较大,算法则会浪费较多的时间和空间来搜索最优解。

3、算法流程

禁忌搜索算法的一般流程如下:

(1)初始化TS算法的参数,按照准则生成问题的初始解,生成0禁忌表;

(2)判断是否满足终止条件,若是,则结束算法,输出结果

(3)根据算法的特性生成领域解,并从中选择合适规模大小的候选解;

(4)判断候选解中的最优解Next是否满足特赦准则,若满足特赦准则,则用Next替代当前最优解Before,并更新禁忌表,令Next对应的禁忌对象的禁忌长度为最长,即禁忌时间最长;若不满足特赦准则,进行(4)步骤;

(5)判断候选解中禁忌状态情况,找出候选解中处于“非禁忌”状态的禁忌对象,并把该禁忌对象对应的解赋给当前最优解,同时设置该禁忌对象的禁忌时间为最长;

(6)转(2);

4、实例及Matlab代码

接下来,利用Tabu Search算法来解决TSP问题。假设有48个随机分布的城市如下图所示,一个旅行商从一个城市出发,遍历完所有城市,要求其旅行距离最短。在这一过程中,禁忌对象为互换城市对,就是在解中把两个城市的位置调换。

function TspTBout = TSPTabusearch(xy,dmat,TabuLength,IterNum,showProg,showResult)
%运用禁忌搜索算法解决TSP问题
nargs = 6;
%检查函数输入
for i = nargin:nargs-1 %nargin代表函数已输入参数个数
    switch i 
        case 0 %产生城市坐标
            xy =[488,814;1393,595;2735,2492;4788,4799;4825,1702;789,2927;4853,1120;4786,3757;2427,1276;4002,2530;710,3496;2109,4455;4579,4797;3962,2737;4798,694;3279,747;179,1288;4246,4204;4670,1272;3394,4072;3789,1218;3716,4647;
                1962,1750;3278,983;856,1256;3531,3081;160,2367;1385,1759;231,4155;486,2927;4118,2749;3475,4586;1586,1430;4752,3787;173,3769;2194,1903;1908,2840;3828,380;3976,270;935,2654;2449,3896;2228,4671;3232,650;3547,2845;3774,2347;1381,60;3399,1686;3276,811];
        case 1%计算距离矩阵
            N = size(xy,1);
            a =meshgrid(1:N);%生成N*N升序矩阵
            dmat = reshape(sqrt(sum((xy(a,:)-xy(a',:)).^2,2)),N,N);% '为矩阵的转置,reshape把数据生成N*N的矩阵
        case 2%设置禁忌长度(禁忌时间)
            TabuLength = round((N*(N-1)/2)^0.5);%round四舍五入
        case 3%设置迭代次数
            IterNum = 1e3;
        case 4%是否展示迭代过程
            showProg = 1;
        case 5%是否展示最终结果
            showResult = 1;
        otherwise
    end
end
%对输入参数进行检查
[N,~] = size(xy);%城市个数、维数
[nr,nc] = size(dmat);%距离矩阵的行数和列数
if N~=nr || N~=nc
    error('城市坐标或距离矩阵输入有误')
end
showProg = logical(showProg(1));%将数值转变为逻辑值
showResult = logical(showResult(1));
%画出城市位置分布图
figure(1);
plot (xy(:,1),xy(:,2),'k.');
title('城市坐标位置');

%% 禁忌搜索算法参数设置
TabuList = zeros(N);%禁忌表设置为城市互换对,为N*N的矩阵,矩阵中的值代表禁忌长度,初始禁忌长度为0
CandidatesNum = 200; %领域解的个数,由领域解选出候选解
Candidates = zeros(CandidatesNum,N);%领域解集合
S0 = randperm(N);%随机产生一个初始解
Broute = S0;%当前最佳的路劲
Bdist = Inf;%当前最佳路径总距离
BLHistory = zeros(IterNum,1);%记录最优路径长度

%% 禁忌搜索循坏
for iter = 1:IterNum
    %% 以下生成城市互换对矩阵Twocity[200,2]
    Twocity = zeros(CandidatesNum,2);
    i = 1;
    while i<= CandidatesNum
        M = ceil(N*rand(1,2));%随机生成两个城市序号
        if M(1) ~= M(2)
            Twocity(i,1) = max(M(1),M(2));%最小值存在1,最大值存在2
            Twocity(i,2) = min(M(1),M(2));
            if i ==1
                isa = 0;%是否生成相同的城市互换对,1为生成了
            else
                for j = 1:i-1
                    if Twocity(i,1)==Twocity(j,1)&&Twocity(i,2)==Twocity(j,2)
                        %若相同
                        isa =1;
                        break;
                    else
                        isa =0;
                    end
                end
            end
            if ~isa %若生成的城市对与之前的都不相同则可以继续生成城市对
                i =i+1;
            end
        end
    end
   %% 产生领域解,选取前100个为候选解 
     %保留前100个最好领域解为候选解
     BestCandNum = 100;
     %定义一个表格,四列,分别存储领域解序号i,路径长度L(i),Twocity(i,1),Twocity(i,2)
     BCandidate = Inf * ones(BestCandNum,4);
     L = zeros(1,CandidatesNum);
     %相当于产生一个S0的解,包含有200个领域解,从中找出最佳的100个才是候选解
     for i = 1:CandidatesNum
         Candidates(i,:) = S0;%领域解
         Candidates(i,[Twocity(i,2),Twocity(i,1)]) = S0([Twocity(i,1),Twocity(i,2)]);%在当前解S0上交换两个城市的位置
         %计算当前领域解路径的距离
         L(i) = CalDistofS(dmat,Candidates(i,:));
         
         %选出100个最好的领域解充当候选解
         if i<= BestCandNum
            BCandidate(i,1) = i;
            BCandidate(i,2) = L(i);
            BCandidate(i,3) = S0(Twocity(i,1));
            BCandidate(i,4) = S0(Twocity(i,2));
         else
             for j =1:BestCandNum
                if L(i) < BCandidate(j,2)%领域解超出100个,则需要比较选取较小距离的
                    BCandidate(j,1) = i;
                    BCandidate(j,2) = L(i);
                    BCandidate(j,3) = S0(Twocity(i,1));
                    BCandidate(j,4) = S0(Twocity(i,2));
                    break;
                end
             end
         end
     end
     %根据距离,对候选解进行排序
     [~,Index] = sort(BCandidate(:,2));%Index是BCandidate中距离升序排列后的索引
     SBest = BCandidate(Index,:);
     BCandidate = SBest;% 此时的BCandidate是按第二列路径长度升序排列的
     %% 特赦准则是否满足,更新禁忌表
     if BCandidate(1,2)< Bdist%如果小于当前最优
         Bdist = BCandidate(1,2);
         %当前最优解变为候选解中的第BCandidate(1,1)行
         S0 = Candidates(BCandidate(1,1),:);
         Broute = S0;
         for m = 1:N
             for n = 1:N
                 if TabuList(m,n) ~=0
                     TabuList(m,n) = TabuList(m,n) -1;%更新禁忌表,禁忌长度减1
                 end
             end
         end
         TabuList(BCandidate(1,3),BCandidate(1,4)) = TabuLength;%更新禁忌表
     else %若没有找到比当前最优解更好的解
         for i = 1:BestCandNum
             if TabuList(BCandidate(i,3),BCandidate(i,4)) == 0%如果已经解禁了
                 S0 = Candidates(BCandidate(i,1),:);
                 for m = 1:N
                     for n = 1:N
                         if TabuList(m,n) ~=0
                           TabuList(m,n) = TabuList(m,n) -1;%更新禁忌表,禁忌长度减1
                         end
                     end
                 end
                 TabuList(BCandidate(i,3),BCandidate(i,4)) = TabuLength;%更新禁忌表
                 break;
             end
         end
     end
     %更新当前最好解的距离值
     BLHistory(iter,1) = Bdist;
     if showProg
         figure(2);
         for i = 1:(N-1)
             plot([xy(Broute(i),1),xy(Broute(i+1),1)],[xy(Broute(i),2),xy(Broute(i+1),2)],'bo-');%画出路线图
             hold on;
         end
          plot([xy(Broute(N),1),xy(Broute(1),1)],[xy(Broute(N),2),xy(Broute(1),2)],'ro-');%画出终点到起点的线
          title(['迭代次数:', num2str(iter),'最短距离:',num2str(Bdist)]);
          hold off;
     end
end
if showResult
    Bestroute = Broute;
    MinLength = Bdist;
    figure(3);
    plot(BLHistory,'b');%画出最优路径长度与迭代次数的关系
    xlabel('迭代次数');
    ylabel('当前最优路径长度');
    title('最优路径长度变化曲线图');
    grid;
    hold on;  
end
if nargout%如果需要输出结果
    TspTBout{1} = Bestroute;
    TspTBout{2} = MinLength;
end

function L = CalDistofS(dmat,S)
     dist = 0;
     n = size(S,2);
     for k = 1:(n-1)
         dist = dist +dmat(S(k),S(k+1));%中间路径的距离
     end
     L = dist + dmat(S(n),S(1));%回到起点的距离
end

end

 

由于代码有较多的注释,就不在解释太多了,直接上结果图吧!

若有小伙伴对机器人任务分配算法较为兴趣的,可以在下面评论交流一波,纯属互相学习!

  • 28
    点赞
  • 121
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
禁忌搜索算法Tabu Search)是一种启发式搜索算法,用于解决组合优化问题。下面是一个简单的禁忌搜索算法Matlab完整代码示例: ```matlab % 定义问题的目标函数 function f = objective_function(x) % 在这里定义你的目标函数 % 输入参数x是待优化的变量 % 返回值f是目标函数的值 end % 定义禁忌搜索算法 function [best_solution, best_fitness] = tabu_search(initial_solution, tabu_list_size, max_iterations) % 初始化禁忌表 tabu_list = zeros(tabu_list_size, 1); % 初始化当前解和最佳解 current_solution = initial_solution; best_solution = initial_solution; % 计算当前解和最佳解的适应度值 current_fitness = objective_function(current_solution); best_fitness = current_fitness; % 开始迭代搜索 for iteration = 1:max_iterations % 生成当前解的邻域解集合 neighborhood = generate_neighborhood(current_solution); % 选择邻域中最佳的非禁忌解作为下一个解 next_solution = select_best_neighbor(neighborhood, tabu_list); % 更新禁忌表 tabu_list = update_tabu_list(tabu_list, next_solution); % 更新当前解和最佳解 current_solution = next_solution; current_fitness = objective_function(current_solution); if current_fitness < best_fitness best_solution = current_solution; best_fitness = current_fitness; end end end % 生成当前解的邻域解集合 function neighborhood = generate_neighborhood(solution) % 在这里定义如何生成当前解的邻域解集合 % 输入参数solution是当前解 % 返回值neighborhood是邻域解集合 end % 选择邻域中最佳的非禁忌解作为下一个解 function next_solution = select_best_neighbor(neighborhood, tabu_list) % 在这里定义如何选择邻域中最佳的非禁忌解作为下一个解 % 输入参数neighborhood是邻域解集合 % 输入参数tabu_list是禁忌表 % 返回值next_solution是下一个解 end % 更新禁忌表 function updated_tabu_list = update_tabu_list(tabu_list, solution) % 在这里定义如何更新禁忌表 % 输入参数tabu_list是禁忌表 % 输入参数solution是当前解 % 返回值updated_tabu_list是更新后的禁忌表 end % 示例使用 initial_solution = [1, 2, 3, 4, 5]; % 设置初始解 tabu_list_size = 10; % 设置禁忌表大小 max_iterations = 100; % 设置最大迭代次数 [best_solution, best_fitness] = tabu_search(initial_solution, tabu_list_size, max_iterations); disp('最佳解:'); disp(best_solution); disp('最佳适应度值:'); disp(best_fitness); ``` 请注意,上述代码中的一些函数(如`objective_function`、`generate_neighborhood`、`select_best_neighbor`和`update_tabu_list`)需要根据你的具体问题进行实现。你需要根据你的问题定义目标函数和邻域生成方式,并根据禁忌搜索算法的要求选择最佳邻域解和更新禁忌表的策略。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小吴伴学者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值