禁忌搜索算法(Tabu Search,TS) C++代码思路

参考博客

1.【算法】禁忌搜索算法(Tabu Search,TS)超详细通俗解析附C++代码实例
https://www.cnblogs.com/dengfaheng/p/9737556.html
给出了源码数据文件,“兔子爬山”这个比喻通俗易懂。

2.禁忌搜索(Tabu Search)算法及python实现
https://blog.csdn.net/adkjb/article/details/81712969
举例详述TS算法过程”这一章节,给出了候选集合禁忌表的表格,便于大家理解TS

3.禁忌搜索算法详解
https://blog.csdn.net/tyhj_sf/article/details/54235550
引言”给出了优化问题相关算法的分类,虽然我没接触过具体算法,但是挺喜欢这种图表总结。
禁忌搜索算法”简介明了,本文正文多参考于此博客
总结”用兔子们给出了对爬山法模拟退火禁忌搜索遗传算法的理解。虽然我没接触过,但会收藏,防日后用到。
强烈推荐此博客!!!

TS算法思想

标记已经解得的局部最优解或求解过程,并在进一步的迭代中避开这些局部最优解或求解过程。为了找到全局最优解,禁忌搜索就是对于找到的一部分局部最优解,通过设置禁忌表,有意识地避开它,从而或得更多的搜索区域。

TS算法步骤

(1)给定一个禁忌表(Tabu List)H=null,并选定一个初始解X_now.
(2)如果满足停止规则,则停止计算,输出结果;
否则算法继续进行
(3)在X_now的领域中选出候选集N(X_now),找出N个最优解作为候选解C(X_now)
(4)如果C中禁忌的候选解满足特赦原则,则把该解当做当前最优解X_next;
否则,求出C中非禁忌的最优解X_next
(5) 如果X_next<X_now,则更新X_now=X_next
更新历史记录H, 将X_next加入禁忌表。
(6)重复步骤(2).

对搜索性能有影响的因素

禁忌表

禁忌表包括禁忌对象禁忌长度。由于在每次对当前解的搜索中,需要避免一些重复的步骤,因此将某些元素放入禁忌表中,这些元素在下次搜索时将不会被考虑,这些被禁止搜索的元素就是禁忌对象
禁忌长度则是被禁对象不允许选取的迭代次数,若设置的太多则可能会造成耗时较长或者算法停止,若太少则会造成重复搜索。

特赦规则

通俗定义:对于在禁忌的对象,如果出现以下情况,不论现在对象的禁忌长度如何,均设为0:
(1)基于评价值的规则,若出现一个解的目标值好于前面任何一个最佳候选解,可特赦;
(2)基于最小错误的规则,若所有对象都被禁忌,特赦一个评价值最小的解;
(3)基于影响力的规则,可以特赦对目标值影响大的对象。

候选集

候选集的大小,过大增加计算内存和计算时间,过小过早陷入局部最优。候选集的选择一般由邻域中的邻居组成,可以选择所有邻居,也可以选择表现较好的邻居,还可以随机选择几个邻居。

评价函数

评价函数分为直接评价函数和间接评价函数。
直接评价函数:上述例子,均直接使用目标值作为评价函数。
间接评价函数:反映目标函数特性的函数(会比目标函数的计算更为简便,用以减少计算时间等)。

终止规则

禁忌算法是一个启发式算法,我们不可能让搜索过程无穷进行,所以一些直观的终止规则就出现了
(1)确定步数终止,无法保证解的效果,应记录当前最优解;
(2)频率控制原则,当某一个解、目标值或元素序列的频率超过一个给定值时,终止计算;
(3)目标控制原则,如果在一个给定步数内,当前最优值没有变化,可终止计算。

本文程序中,相关参数如下

禁忌长度10
特设原则:若所有对象都被禁忌出现一个解的目标值好于前面任何一个最佳候选解特赦一个评价值最小的解
候选集选择所有邻居,邻居大小为N*(N-1)/2,N为当前tsp文件中城市的个数
评价函数:直接使用目标值作为评价函数,TSP问题中是总旅程距离
终止规则:确定迭代次数终止,为100

TS算法代码笔记

在这里插入图片描述

TS算法代码思路

main函数

  1. 定义tsp文件的绝对路径,即tsp文件存放的位置
    通过键盘输入的0~9,得到tsp文件的相对路径,最后读取对应的tsp文件
    如果文件打开失败,则提示
  2. 从tsp文件读入城市数n,及城市之间的相对距离adj
  3. 计算TabuSearch函数的运行时间,并显示相应的结果
  4. 关闭打开的tsp文件

注:新的tsp文件可能增加了新的文本,我们需要把城市数(如gr17.tsp中的17)附到EDGE_WEIGHT_SECTION后边的0之前,然后删除EDGE_WEIGHT_SECTION及之前的所有内容。

在这里插入图片描述

TabuSearch函数

根据形参n的到城市数N,并定义邻居大小**N*(N-1)/2*

			NEIGHBOUR_SIZE = N * (N - 1) / 2;

计算邻居中所有可能的情况,并存于tabuList 的第0列和第1列,第二列为距离和,默认赋值INF

			tabuList[i][0] = j;
            tabuList[i][1] = k;
            tabuList[i][2] = INF;

生成城市之间的随机序列号,并计算该序列号对应的最佳距离bestDis

			CreateRandOrder(city1, N);
       		bestDis = GetPathLen(city1, N);

将city1内容复制到city2

 		    memcpy(city2, city1, sizeof(city2)); 

求出每次邻居交换后序列对应的距离和

			swap(city2[a], city2[b]);
            tmpDis = GetPathLen(city2, N);

如果解在禁忌列表中,则禁忌表中对应的距离设为INF,并将解得相关信息存入pardon备用
如果解不在禁忌列表中,则把当前最优解加入禁忌表

			if (tabuList[countN][3] > 0)
			{ 
            	tabuList[countN][2] = INF; 
                if (tmpDis < pardon[1])
				{
                	pardon[0] = countN;
                    pardon[1] = tmpDis;
                }
            }
            else 
			{
                   tabuList[countN][2] = tmpDis;
            }

遍历求得非禁忌中的最优解,并将相关信息存入当前最优解curBest

			 for (int i = 0; i < NEIGHBOUR_SIZE; i++)
			 {
                if (tabuList[i][3] == 0 && tabuList[i][2] < curBest[1])
				{
                    curBest[0] = i;
                    curBest[1] = tabuList[i][2];
                }
            }

如果若所有对象都被禁忌或出现一个解的目标值好于前面任何一个最佳候选解 bestDis特赦该解

			if (curBest[0] == INF || pardon[1] < bestDis) 
			{
                curBest[0] = pardon[0];
                curBest[1] = pardon[1];
            }

如果当前最优解curBest小于最佳距离bestDis,则更新bestDis并把给curBest对应的序列设置禁忌

			if (curBest[1] < bestDis)
			{
                bestDis = curBest[1];
                tabuList[curBest[0]][3] = TABU_SIZE;
                bestIteration = ITERATIONS - countI;
                a = tabuList[curBest[0]][0];
                b = tabuList[curBest[0]][1];
                swap(city1[a], city1[b]);
            }      

更新tabuList中的禁忌长度

			UpdateTabuList(NEIGHBOUR_SIZE);

更新全局最优解finalDis,并得到其对应的城市序列号path
25次循环后将返回finalDis给main()的distance

			if (bestDis < finalDis)
			{
            	finalDis = bestDis;
            	memcpy(path, city1, sizeof(path));
       	    }

运行结果

修改了部分代码,与源码界面不太一样,不过不影响理解。
在这里插入图片描述

致谢

感谢东南苏神给我找BUG,调程序。

菜鸡解读必有不妥之处,欢迎各位大神批评指正!
感谢各个博客平台上各位大神给出的代码及思路,感激不尽~

发布了24 篇原创文章 · 获赞 15 · 访问量 5389

猜你喜欢

转载自blog.csdn.net/qq_34122861/article/details/90229689