禁忌搜索算法求解TSP旅行商问题C++(2020.11.19)

  • Post author:
  • Post category:其他




1、禁忌搜索算法

禁忌搜索算法(tabu search/taboo search,TS)是一种模拟人类记忆功能特性的全局性搜索算法。它最初是由Glover提出的,主要用于解决组合优化问题,与局部优化法相比陷入局部极小值的概率更小,比遗传算法、模拟退火算法更易于利用问题的特殊信息。因此,它具有很强的全局搜索能力,在复杂问题和大型问题上有特殊的效果。禁忌搜索算法是对人类思维过程本身的一种模拟,它通过对一些局部最优解的禁忌(也可以说是记忆)达到接纳一部分较差解,从而跳出局部搜索的目的。

“禁忌”就是禁止重复前面的工作,是一种强加的限制。禁忌搜索算法采用了禁忌技术和解空间进行搜索,避免了陷入局部最优,从而具有全局搜索能力。“禁忌准则”和“特赦准则”使该算法具有很强的“爬山”能力,因而具有智能性。禁忌搜索算法通过局部搜索机制和相应的禁忌准则来避免迂回搜索,并通过特赦准则来释放一些被禁忌的优良解,进而保证多样化的有效搜索,但存在收敛速度较慢的缺陷。禁忌搜索算法已在组合优化、生产调度、资源规划、机器学习、数据挖掘、函数优化和生态环境评价等多个领域获得了广泛应用。



1.1 基本思想及主要特点

禁忌搜索算法的基本思想是:假设给出一个解邻域,首先在解邻域中找出一个初始局部解



x

x






x





作为当前解,并令当前解为最优解



x

x^{‘}







x













































,然后以这个当前解作为起点,在解邻域中搜索最优解 。当然,这个最优解可能与前一次所得的最优解相同,为了避免这种循环现象的出现,设置一个记忆近期操作的禁忌表,如果当前的搜索操作是记录在此表中的操作,那么这一搜索操作就被禁止;否则用



x

x^{‘}







x













































取代



x

x






x





作为当前解。但禁忌表有可能限制某些可以导致更好解的“移动”。为了尽可能不错过产生最优解的“移动”,若满足特赦准则,即使它处于禁忌表中,这个移动也可实现。

禁忌搜索算法的主要特点是:①在搜索过程中可接受劣解,因而具有较强的“爬山”能力。②新解不是在当前解的邻域中随机产生,而是或优于当前最优解,或是非禁忌的最佳解,因而获得优良解的概率远大于其他解。

作为一种启发式算法,禁忌搜索算法也有明显不足:①对初始解有较强的依赖性,一个较差的初始解则会降低禁忌搜索的收敛速度。②迭代搜索过程是串行的,仅是单一状态的非并行搜索。



1.2 基本概念

禁忌搜索算法有关的基本概念包括:禁忌表(tabu list)、邻域(neighbourhood)、禁忌条件(tabu condition)、特赦准则(aspiration level)及终止准则(termination criterion)等。

禁忌表。禁忌表是禁忌搜索算法的核心,禁忌对象和禁忌长度是禁忌表的两个关键指标。禁忌表的长度可以固定,也可以改变。处在禁忌表中的移动在近期的迭代中是被禁止的,除非满足特赦准则。邻域结构、禁忌对象、禁忌长度、特赦准则和终止准则是与禁忌搜索算法的搜索效率和求解质量直接相关的关键要素。

邻域。对于



X

X






X





中的每一解



x

x






x





的邻域定义为:当前解



x

x






x





所有可行移动



S

(

x

)

S(x)






S


(


x


)





而形成的解的集合称为解



x

x






x





的邻域



N

(

x

)

N(x)






N


(


x


)





,通常表现为以解



x

x






x





为中心,



r

r






r





为半径的球



B

(

x

,

x

)

B(x,x^{‘})






B


(


x


,





x










































)





。从而所有满足



x

x

r

||x^{‘}-x||≤r













x





















































x



















r





的点



x

x^{‘}







x













































的集合均为



x

x






x





的邻域解。其中



||\cdot||
































为范数。

禁忌条件。禁忌条件是通过禁忌表来实现的。为了避免陷入局部极小点,算法禁止一定时间内走过的区域。每运行一步,都将当前点及其目标函数值放入禁忌表中,作为禁忌区域的中心。禁忌表的长度固定为



T

L

TL






T


L





,当禁忌表已满,即里面有



T

L

TL






T


L





个元素时,将最早进入的元素从禁忌表中释放,并把新的元素放入表中。

可用两重判断准则来判断一个点



x

x






x





是否被禁忌。第一准则为首先判断点的目标函数值



f

(

x

)

f(x)






f


(


x


)





。如果



f

(

x

)

f(x)






f


(


x


)





跟禁忌表中的任一个函数值



f

L

(

x

)

f_{L}(x^{*})







f











L



















(



x






















)





都不接近,即对任一



f

L

(

x

)

f_{L}(x^{*})







f











L



















(



x






















)





都有



f

(

x

)

f

L

(

x

)

>

ε

|f(x)-f_{L}(x^{*})|>ε









f


(


x


)














f











L



















(



x






















)







>








ε









ε

ε






ε





为给定值),则点



x

x






x





不被禁忌,否则判断第二准则。

第二准则判断点



x

x






x





。如果 的目标函数值跟禁忌表中点的函数值接近,则判断点



x

x






x





跟点



x

x^{‘}







x













































是否接近。如果对任一



x

j

(

j

=

1

,

2

,

.

.

.

,

n

)

x_{j}(j=1,2,…,n)







x











j



















(


j




=








1


,




2


,




.


.


.


,




n


)





都有



x

j

x

j

ε

|x_{j}-x_{j}^{*}|≤ε










x











j































x











j












































ε





,则点



x

x






x





被禁忌,否则不被禁忌。

两重准则可以减少计算量。例如,对于



n

n






n





维变量,判断一定点是否在一个矩形区域内要做



n

n






n





次比较,而函数值的比较只需要做一次计算即可。

特赦规则。特赦规则的作用是防止某些更优点被禁忌,满足特赦规则的点无需判断是否被禁忌,可以直接选取作为新的当前点。特赦规则可定义为:如果点



x

x






x





的目标函数值优于目前为止搜索到的最优点的目标函数值,说明点



x

x






x





满足特赦规则,则被选取为新的当前点。

终止规则当达到最大迭代步数,或在给定的迭代步数内算法搜索到的最优点没有改善时,算法将终止迭代。



1.3 算法流程

基本禁忌搜索算法步骤如下:



步骤1


:随机生成一个初始点



x

0

x_{0}







x











0






















,计算它的目标函数值



f

(

x

0

)

f(x_{0})






f


(



x











0



















)





,初始化当前点



x

=

x

0

x=x_{0}






x




=









x











0






















,最优点



x

b

e

s

t

=

x

0

x_{best}=x_{0}







x











b


e


s


t





















=









x











0






















,最优点的目标函数值



f

(

x

b

e

s

t

)

=

f

(

x

0

)

f(x_{best})=f(x_{0})






f


(



x











b


e


s


t



















)




=








f


(



x











0



















)








步骤2


:生成当前点



x

x






x





的邻域,计算出邻域内各点的目标函数值。



步骤3


:选邻域内目标函数值最优的点



x

x^{*}







x





























步骤4


:判断特赦规则。如果满足特赦规则,则新的当前点移到



x

x^{*}







x

























,即



x

=

x

x=x^{*}






x




=









x

























,同时更新最优点



x

b

e

s

t

=

x

x_{best}=x^{*}







x











b


e


s


t





















=









x





























f

(

x

b

e

s

t

)

=

f

(

x

)

f(x_{best})=f(x^{*})






f


(



x











b


e


s


t



















)




=








f


(



x






















)





,转到步骤6,否则转到步骤5.



步骤5


:判断点



x

x^{*}







x

























是否被禁忌,如果点



x

x^{*}







x

























未被禁忌,则将新的当前点移动到



x

x^{*}







x

























,转到步骤6,否则将



x

x^{*}







x

























从邻域中删除,转到步骤3.



步骤6


:更新禁忌表,并判断终止规则。若满足终止规则,则终止运算,否则转到步骤2。



2、 TS求解TSP问题的C++实现



2.1 输入数据文件:bayg29.tsp

   1    1150.0  1760.0
   2     630.0  1660.0
   3      40.0  2090.0
   4     750.0  1100.0
   5     750.0  2030.0
   6    1030.0  2070.0
   7    1650.0   650.0
   8    1490.0  1630.0
   9     790.0  2260.0
  10     710.0  1310.0
  11     840.0   550.0
  12    1170.0  2300.0
  13     970.0  1340.0
  14     510.0   700.0
  15     750.0   900.0
  16    1280.0  1200.0
  17     230.0   590.0
  18     460.0   860.0
  19    1040.0   950.0
  20     590.0  1390.0
  21     830.0  1770.0
  22     490.0   500.0
  23    1840.0  1240.0
  24    1260.0  1500.0
  25    1280.0   790.0
  26     490.0  2130.0
  27    1460.0  1420.0
  28    1260.0  1910.0
  29     360.0  1980.0



2.2 头文件

#include <iostream>
#include <fstream>
#include <string>
#include <random>
#include <time.h>
using namespace std;



2.3 所需的类

所需的类包括

城市类City



包含城市的地图类Graph



禁忌搜索算法类SA



2.3.1 城市类City

class City
{
public:
	string name;//城市名称
	double x, y;//城市点的二维坐标
	void shuchu()
	{
		std::cout << name + ":" << "(" << x << "," << y << ")" << endl;
	}
};



2.3.2 包含城市的地图类Graph

class Graph
{
public:
	int Citycount;
	City *city;//城市数组
	double distance[citycount][citycount];//城市间的距离矩阵
	void Readcoordinatetxt(string txtfilename)//读取城市坐标文件的函数
	{
		Citycount = citycount;
		city = new City[Citycount];
		ifstream myfile(txtfilename, ios::in);
		double x = 0, y = 0;
		int z = 0;
		if (!myfile.fail())
		{
			int i = 0;
			while (!myfile.eof() && (myfile >> z >> x >> y))
			{
				city[i].name = to_string(_Longlong(z));//城市名称转化为字符串
				city[i].x = x; city[i].y = y;
				i++;
			}
		}
		else
			cout << "文件不存在";
		myfile.close();//计算城市距离矩阵
		for (int i = 0; i < citycount; i++)
			for (int j = 0; j < citycount; j++)
			{
				distance[i][j] = sqrt((pow((city[i].x - city[j].x), 2) + pow((city[i].y - city[j].y), 2)) / 10.0);//计算城市ij之间的伪欧式距离
				if (round(distance[i][j] < distance[i][j]))distance[i][j] = round(distance[i][j]) + 1;
				else distance[i][j] = round(distance[i][j]);
			}
	}
	void shuchu()
	{
		cout << "城市名称 " << "坐标x" << " " << "坐标y" << endl;
		for (int i = 0; i < citycount; i++)
			city[i].shuchu();
		cout << "距离矩阵: " << endl;
		for (int i = 0; i < citycount; i++)
		{
			for (int j = 0; j < citycount; j++)
			{
				if (j == citycount - 1)
					std::cout << distance[i][j] << endl;
				else
					std::cout << distance[i][j] << "  ";
			}
		}
	}
};



2.3.3 禁忌搜索算法类TS

class TS
{
public:
	int x0[citycount];//初始解
	int xbest[citycount];//最优解
	int xlocalbest[citycount];//邻域内的局部最优解
	double bestdisvalue,localbestdisvalue;//最优解对应的距离值、邻域内最优解对应距离值
	int N,Neighborcount,TL,Itetime;//每次搜索邻域的数目、禁忌表的长度、迭代次数
	int **xNeighbor;//x邻域的Neigghborcount个解
	int **TabuTable,currentjinjicount;//禁忌表、禁忌表中当前被禁忌解的个数
	void Init(int neighborcount,int tl,int itetime)//初始化函数
	{
		Neighborcount = neighborcount;
		TL = tl;
		Itetime = itetime;
		currentjinjicount = 0;
		int *b;
		b = Random_N(citycount);
		for (int i = 0; i < citycount; i++)
		{
			x0[i] = b[i];
			xbest[i] = x0[i];
		}
		bestdisvalue = Evaluate(xbest);
	   TabuTable = new int*[TL];
	   for (int i = 0; i < TL; i++)
		   TabuTable[i] = new int[citycount];
	   xNeighbor = new int *[Neighborcount];
	   for (int i = 0; i < Neighborcount; i++)
		   xNeighbor[i] = new int[citycount];
	}
	double Evaluate(int X[citycount])//计算解对应目标距离值的函数
	{
		double funvalue = 0;
		for (int i = 0; i < citycount - 1; i++)
			funvalue += Map_City.distance[X[i] - 1][X[i + 1] - 1];
		funvalue += Map_City.distance[X[citycount - 1] - 1][X[0] - 1];
		return funvalue;
	}
	void GetNeighborhood(int X[citycount], int tempX[citycount])//通过邻域交换来得到邻域解的函数
	{
		for (int i = 0; i < citycount; i++)
			tempX[i] = X[i];
		int random1, random2;
		random1 = rand() % citycount;
		while (true)
		{
			random2 = rand() % citycount;
			if (random2 != random1)break;
		}
		int temp;
		temp = tempX[random1];
		tempX[random1] = tempX[random2];
		tempX[random2] = temp;
	}
	bool PanduanTabuTable(int X[citycount])//判断解是否被禁忌的函数
	{
		if (currentjinjicount == 0) return false;
		else
		{
			int flag = 0;
			for (int i = 0; i < currentjinjicount; i++)
			{
				flag = 1;
				int j = 0;
				for (; j < citycount; j++)
				{
					if (TabuTable[i][j] != X[j])
					{
						flag = 0;//解不在禁忌表中
						break;
					}
				}
				if (flag == 1) break;
			}
			if (flag == 1)//解在禁忌表中
				return true;
			else//解不在禁忌表中
				return false;
		}
	}
	bool PanduanTeShe(int X[citycount])//判断是否满则特赦规则
	{
		if (Evaluate(X) < bestdisvalue) return true;
		else return false;
	}
	void UpdateTabuTable(int X[citycount])//更新禁忌表的函数
	{
		if (currentjinjicount == TL)//禁忌表满了
		{
			//删除禁忌表中第一个解,同时将禁忌表后面的解往前挪
			for (int i = 0; i < TL - 1; i++)
			{
				for (int j = 0; j < citycount; j++)
					TabuTable[i][j] = TabuTable[i+1][j];
			}
			//将新插入的解放到禁忌表的最后
			for (int j = 0; j < citycount; j++)
				TabuTable[TL-1][j] = X[j];
		}
		else//禁忌表未满
		{
			for (int j = 0; j < citycount; j++)
				TabuTable[currentjinjicount][j] = X[j];
		}
	}
	void  GetNeighborlocalbest(int count)//获取邻域最优解的函数
	{
		int k;
		for (int i = 0; i < count; i++)
		{
			if (PanduanTabuTable(xNeighbor[i]) == false) 
			{
				k = i; break;
			}
		}
		for (int i = 0; i < citycount; i++)
			xlocalbest[i] = xNeighbor[k][i];
		localbestdisvalue = Evaluate(xlocalbest);
		for (int m = 0; m < count; m++)//再搜索count个邻域解,找出目标函数值最优的点x*
		{
			if (PanduanTabuTable(xNeighbor[m]) == false &&Evaluate(xNeighbor[m]) < localbestdisvalue)//xlocalbest未被禁忌
			{
					for (int i = 0; i < citycount; i++)
						xlocalbest[i] = xNeighbor[m][i];
					localbestdisvalue = Evaluate(xlocalbest);
			}
		}
	}
	void TeShe()//执行判断特赦操作的函数
	{
		if (PanduanTeShe(xlocalbest) == true)//如果满足特赦规则
		{
			for (int j = 0; j < citycount; j++)
			{
				x0[j] = xlocalbest[j];
				xbest[j] = xlocalbest[j];
			}
			bestdisvalue = Evaluate(xbest);
			//更新禁忌表
			UpdateTabuTable(xlocalbest);
			if(currentjinjicount < TL) currentjinjicount++;
		}
		else //如果不满足特赦规则
		{
			JinJi();
		}
	}
	void JinJi()//执行判断禁忌操作的函数
	{
		if (PanduanTabuTable(xlocalbest) == false)//xlocalbest未被禁忌
		{
			for (int j = 0; j < citycount; j++)
			{
				x0[j] = xlocalbest[j];
			}
			//更新禁忌表
			UpdateTabuTable(xlocalbest);
		}
		else
		{
			if (N > 1)
			{
				N--;
				GetNeighborlocalbest(N);
			}
		}
	}
	void TS_TSP(int neigh,int tl,int itetime,string filename)
	{
		ofstream outfile;
		outfile.open("result.txt", ios::trunc);
		Map_City.Readcoordinatetxt(filename);
		Map_City.shuchu();
		outfile << "城市名称 " << "坐标x" << " " << "坐标y" << endl;
		for (int i = 0; i < citycount; i++)
			outfile << Map_City.city[i].name << " " << Map_City.city[i].x << " " << Map_City.city[i].y << endl;
		outfile << "距离矩阵: " << endl;
		for (int i = 0; i < citycount; i++)
		{
			for (int j = 0; j < citycount; j++)
			{
				if (j == citycount - 1)
					outfile << Map_City.distance[i][j] << endl;
				else
					outfile << Map_City.distance[i][j] << "  ";
			}
		}
		Init(neigh,tl,itetime);
		outfile << "初始解如下:" << endl;
		for (int i = 0; i < citycount; i++)
		{
			if (i == 0)outfile << "f(" << x0[i] << ",";
			else if (i == citycount - 1) outfile << x0[i] << ") =  " << Evaluate(x0) << endl;
			else outfile << x0[i] << ",";
		}
		for (int t = 0; t < Itetime; t++)
		{
			for (int i = 0; i < Neighborcount; i++)
				GetNeighborhood(x0, xNeighbor[i]);//获取x0的Neighborcount个邻域解
			outfile << "第" << t + 1 << "次迭代的初始解为:";
			for (int i = 0; i < citycount; i++)
			{
				if (i == 0)outfile << "f(" << x0[i] << ",";
				else if (i == citycount - 1) outfile << x0[i] << ") =  " << Evaluate(x0) << endl;
				else outfile << x0[i] << ",";
			}
			outfile << "第" << t + 1 << "次迭代" << Neighborcount << "个邻域解:" << endl;
			for (int i = 0; i < Neighborcount; i++)
			{
				outfile << "邻域解" << i + 1 << ":";
				for (int j = 0; j < citycount; j++)
				{
					if (j == 0)outfile << "f(" << xNeighbor[i][j] << ",";
					else if (j == citycount - 1) outfile << xNeighbor[i][j] << ") =  " << Evaluate(xNeighbor[i]) << endl;
					else outfile << xNeighbor[i][j] << ",";
				}
			}
			N = Neighborcount;//有效的邻域数量
			GetNeighborlocalbest(N);
			TeShe();
			JinJi();
			std::cout << "第" << t + 1 << "次迭代后的最优解为:";
			for (int j = 0; j < citycount; j++)
			{
				if (j == 0)
					std::cout << "f(" << xbest[j] << ",";
				else if (j == citycount - 1)
					std::cout << xbest[j] << ")=" << bestdisvalue << endl;
				else
					std::cout << xbest[j] << ",";
			}
			outfile << "第" << t + 1 << "次迭代后的最优解为:";
			for (int j = 0; j < citycount; j++)
			{
				if (j == 0)
					outfile << "f(" << xbest[j] << ",";
				else if (j == citycount - 1)
					outfile << xbest[j] << ")=" << bestdisvalue << endl;
				else
					outfile << xbest[j] << ",";
			}
		}
		outfile << "迭代结束后的最优解如下:" << endl;
		for (int i = 0; i < citycount; i++)
		{
			if (i == 0)outfile << "f(" << xbest[i] << ",";
			else if (i == citycount - 1) outfile << xbest[i] << ")=" << bestdisvalue << endl;
			else outfile << xbest[i] << ",";
		}
		outfile << "迭代结束后的禁忌表如下:" << endl;
		for (int i = 0; i < currentjinjicount; i++)
		{
			for (int j = 0; j < citycount; j++)
			{
				if (j == 0)outfile << "f(" << TabuTable[i][j] << ",";
				else if (j == citycount - 1) outfile << TabuTable[i][j] << ") =  " << Evaluate(TabuTable[i]) << endl;
				else outfile << TabuTable[i][j] << ",";
			}
		}
		outfile.close();
	}
};



2.4 自定义函数

随机生成TSP问题的一个可行解的函数

int * Random_N(int n)//随机生成TSP问题的一个可行解的函数
{
	int *geti;
	geti = new int[n];
	int j = 0;
	while (j<n)
	{
		while (true)
		{
			int flag = -1;
			int temp = rand() % n + 1;
			if (j > 0)
			{
				int k = 0;
				for (; k < j; k++)
				{
					if (temp == *(geti + k))break;
				}
				if (k == j)
				{
					*(geti + j) = temp;
					flag = 1;
				}
			}
			else
			{
				*(geti + j) = temp;
				flag = 1;
			}
			if (flag == 1)break;
		}
		j++;
	}
	return geti;
}



2.5 全局变量

std::default_random_engine random((unsigned int)time(NULL));
std::uniform_real_distribution<double> u(0, 1); //随机数分布对象
const int citycount = 29;
Graph Map_City;//定义全局对象图,放在Graph类后



2.6 主函数

int main()
{
	system("mode con cols=200");
	system("color fc");
	TS ts;
	ts.TS_TSP(8, 20, 100, "E:\\计算智能代码\\TS_TSP\\TS_TSP\\bayg29.tsp");
	system("pause");
	return 0;
}



2.7 运行结果

运行结果分为控制台运行结果和生成的result.txt文件结果



2.7.1 控制台运行结果

在这里插入图片描述

在这里插入图片描述



2.7.2 生成result.txt文件结果

在这里插入图片描述

在这里插入图片描述



2.8 MATLAB绘制最优路径结果

在这里插入图片描述



附录(完整代码)

#include <iostream>
#include <fstream>
#include <string>
#include <random>
#include <time.h>
using namespace std;
std::default_random_engine random((unsigned int)time(NULL));
std::uniform_real_distribution<double> u(0, 1); //随机数分布对象
const int citycount = 29;
class City
{
public:
	string name;//城市名称
	double x, y;//城市点的二维坐标
	void shuchu()
	{
		std::cout << name + ":" << "(" << x << "," << y << ")" << endl;
	}
};
class Graph
{
public:
	int Citycount;
	City *city;//城市数组
	double distance[citycount][citycount];//城市间的距离矩阵
	void Readcoordinatetxt(string txtfilename)//读取城市坐标文件的函数
	{
		Citycount = citycount;
		city = new City[Citycount];
		ifstream myfile(txtfilename, ios::in);
		double x = 0, y = 0;
		int z = 0;
		if (!myfile.fail())
		{
			int i = 0;
			while (!myfile.eof() && (myfile >> z >> x >> y))
			{
				city[i].name = to_string(_Longlong(z));//城市名称转化为字符串
				city[i].x = x; city[i].y = y;
				i++;
			}
		}
		else
			cout << "文件不存在";
		myfile.close();//计算城市距离矩阵
		for (int i = 0; i < citycount; i++)
			for (int j = 0; j < citycount; j++)
			{
				distance[i][j] = sqrt((pow((city[i].x - city[j].x), 2) + pow((city[i].y - city[j].y), 2)) / 10.0);//计算城市ij之间的伪欧式距离
				if (round(distance[i][j] < distance[i][j]))distance[i][j] = round(distance[i][j]) + 1;
				else distance[i][j] = round(distance[i][j]);
			}
	}
	void shuchu()
	{
		cout << "城市名称 " << "坐标x" << " " << "坐标y" << endl;
		for (int i = 0; i < citycount; i++)
			city[i].shuchu();
		cout << "距离矩阵: " << endl;
		for (int i = 0; i < citycount; i++)
		{
			for (int j = 0; j < citycount; j++)
			{
				if (j == citycount - 1)
					std::cout << distance[i][j] << endl;
				else
					std::cout << distance[i][j] << "  ";
			}
		}
	}
};
Graph Map_City;//定义全局对象图,放在Graph类后
int * Random_N(int n)//随机生成TSP问题的一个可行解的函数
{
	int *geti;
	geti = new int[n];
	int j = 0;
	while (j<n)
	{
		while (true)
		{
			int flag = -1;
			int temp = rand() % n + 1;
			if (j > 0)
			{
				int k = 0;
				for (; k < j; k++)
				{
					if (temp == *(geti + k))break;
				}
				if (k == j)
				{
					*(geti + j) = temp;
					flag = 1;
				}
			}
			else
			{
				*(geti + j) = temp;
				flag = 1;
			}
			if (flag == 1)break;
		}
		j++;
	}
	return geti;
}
class TS
{
public:
	int x0[citycount];//初始解
	int xbest[citycount];//最优解
	int xlocalbest[citycount];//邻域内的局部最优解
	double bestdisvalue,localbestdisvalue;//最优解对应的距离值、邻域内最优解对应距离值
	int N,Neighborcount,TL,Itetime;//每次搜索邻域的数目、禁忌表的长度、迭代次数
	int **xNeighbor;//x邻域的Neigghborcount个解
	int **TabuTable,currentjinjicount;//禁忌表、禁忌表中当前被禁忌解的个数
	void Init(int neighborcount,int tl,int itetime)//初始化函数
	{
		Neighborcount = neighborcount;
		TL = tl;
		Itetime = itetime;
		currentjinjicount = 0;
		int *b;
		b = Random_N(citycount);
		for (int i = 0; i < citycount; i++)
		{
			x0[i] = b[i];
			xbest[i] = x0[i];
		}
		bestdisvalue = Evaluate(xbest);
	   TabuTable = new int*[TL];
	   for (int i = 0; i < TL; i++)
		   TabuTable[i] = new int[citycount];
	   xNeighbor = new int *[Neighborcount];
	   for (int i = 0; i < Neighborcount; i++)
		   xNeighbor[i] = new int[citycount];
	}
	double Evaluate(int X[citycount])//计算解对应目标距离值的函数
	{
		double funvalue = 0;
		for (int i = 0; i < citycount - 1; i++)
			funvalue += Map_City.distance[X[i] - 1][X[i + 1] - 1];
		funvalue += Map_City.distance[X[citycount - 1] - 1][X[0] - 1];
		return funvalue;
	}
	void GetNeighborhood(int X[citycount], int tempX[citycount])//通过邻域交换来得到邻域解的函数
	{
		for (int i = 0; i < citycount; i++)
			tempX[i] = X[i];
		int random1, random2;
		random1 = rand() % citycount;
		while (true)
		{
			random2 = rand() % citycount;
			if (random2 != random1)break;
		}
		int temp;
		temp = tempX[random1];
		tempX[random1] = tempX[random2];
		tempX[random2] = temp;
	}
	bool PanduanTabuTable(int X[citycount])//判断解是否被禁忌的函数
	{
		if (currentjinjicount == 0) return false;
		else
		{
			int flag = 0;
			for (int i = 0; i < currentjinjicount; i++)
			{
				flag = 1;
				int j = 0;
				for (; j < citycount; j++)
				{
					if (TabuTable[i][j] != X[j])
					{
						flag = 0;//解不在禁忌表中
						break;
					}
				}
				if (flag == 1) break;
			}
			if (flag == 1)//解在禁忌表中
				return true;
			else//解不在禁忌表中
				return false;
		}
	}
	bool PanduanTeShe(int X[citycount])//判断是否满则特赦规则
	{
		if (Evaluate(X) < bestdisvalue) return true;
		else return false;
	}
	void UpdateTabuTable(int X[citycount])//更新禁忌表的函数
	{
		if (currentjinjicount == TL)//禁忌表满了
		{
			//删除禁忌表中第一个解,同时将禁忌表后面的解往前挪
			for (int i = 0; i < TL - 1; i++)
			{
				for (int j = 0; j < citycount; j++)
					TabuTable[i][j] = TabuTable[i+1][j];
			}
			//将新插入的解放到禁忌表的最后
			for (int j = 0; j < citycount; j++)
				TabuTable[TL-1][j] = X[j];
		}
		else//禁忌表未满
		{
			for (int j = 0; j < citycount; j++)
				TabuTable[currentjinjicount][j] = X[j];
		}
	}
	void  GetNeighborlocalbest(int count)//获取邻域最优解的函数
	{
		int k;
		for (int i = 0; i < count; i++)
		{
			if (PanduanTabuTable(xNeighbor[i]) == false) 
			{
				k = i; break;
			}
		}
		for (int i = 0; i < citycount; i++)
			xlocalbest[i] = xNeighbor[k][i];
		localbestdisvalue = Evaluate(xlocalbest);
		for (int m = 0; m < count; m++)//再搜索count个邻域解,找出目标函数值最优的点x*
		{
			if (PanduanTabuTable(xNeighbor[m]) == false &&Evaluate(xNeighbor[m]) < localbestdisvalue)//xlocalbest未被禁忌
			{
					for (int i = 0; i < citycount; i++)
						xlocalbest[i] = xNeighbor[m][i];
					localbestdisvalue = Evaluate(xlocalbest);
			}
		}
	}
	void TeShe()//执行判断特赦操作的函数
	{
		if (PanduanTeShe(xlocalbest) == true)//如果满足特赦规则
		{
			for (int j = 0; j < citycount; j++)
			{
				x0[j] = xlocalbest[j];
				xbest[j] = xlocalbest[j];
			}
			bestdisvalue = Evaluate(xbest);
			//更新禁忌表
			UpdateTabuTable(xlocalbest);
			if(currentjinjicount < TL) currentjinjicount++;
		}
		else //如果不满足特赦规则
		{
			JinJi();
		}
	}
	void JinJi()//执行判断禁忌操作的函数
	{
		if (PanduanTabuTable(xlocalbest) == false)//xlocalbest未被禁忌
		{
			for (int j = 0; j < citycount; j++)
			{
				x0[j] = xlocalbest[j];
			}
			//更新禁忌表
			UpdateTabuTable(xlocalbest);
		}
		else
		{
			if (N > 1)
			{
				N--;
				GetNeighborlocalbest(N);
			}
		}
	}
	void TS_TSP(int neigh,int tl,int itetime,string filename)
	{
		ofstream outfile;
		outfile.open("result.txt", ios::trunc);
		Map_City.Readcoordinatetxt(filename);
		Map_City.shuchu();
		outfile << "城市名称 " << "坐标x" << " " << "坐标y" << endl;
		for (int i = 0; i < citycount; i++)
			outfile << Map_City.city[i].name << " " << Map_City.city[i].x << " " << Map_City.city[i].y << endl;
		outfile << "距离矩阵: " << endl;
		for (int i = 0; i < citycount; i++)
		{
			for (int j = 0; j < citycount; j++)
			{
				if (j == citycount - 1)
					outfile << Map_City.distance[i][j] << endl;
				else
					outfile << Map_City.distance[i][j] << "  ";
			}
		}
		Init(neigh,tl,itetime);
		outfile << "初始解如下:" << endl;
		for (int i = 0; i < citycount; i++)
		{
			if (i == 0)outfile << "f(" << x0[i] << ",";
			else if (i == citycount - 1) outfile << x0[i] << ") =  " << Evaluate(x0) << endl;
			else outfile << x0[i] << ",";
		}
		for (int t = 0; t < Itetime; t++)
		{
			for (int i = 0; i < Neighborcount; i++)
				GetNeighborhood(x0, xNeighbor[i]);//获取x0的Neighborcount个邻域解
			outfile << "第" << t + 1 << "次迭代的初始解为:";
			for (int i = 0; i < citycount; i++)
			{
				if (i == 0)outfile << "f(" << x0[i] << ",";
				else if (i == citycount - 1) outfile << x0[i] << ") =  " << Evaluate(x0) << endl;
				else outfile << x0[i] << ",";
			}
			outfile << "第" << t + 1 << "次迭代" << Neighborcount << "个邻域解:" << endl;
			for (int i = 0; i < Neighborcount; i++)
			{
				outfile << "邻域解" << i + 1 << ":";
				for (int j = 0; j < citycount; j++)
				{
					if (j == 0)outfile << "f(" << xNeighbor[i][j] << ",";
					else if (j == citycount - 1) outfile << xNeighbor[i][j] << ") =  " << Evaluate(xNeighbor[i]) << endl;
					else outfile << xNeighbor[i][j] << ",";
				}
			}
			N = Neighborcount;//有效的邻域数量
			GetNeighborlocalbest(N);
			TeShe();
			JinJi();
			std::cout << "第" << t + 1 << "次迭代后的最优解为:";
			for (int j = 0; j < citycount; j++)
			{
				if (j == 0)
					std::cout << "f(" << xbest[j] << ",";
				else if (j == citycount - 1)
					std::cout << xbest[j] << ")=" << bestdisvalue << endl;
				else
					std::cout << xbest[j] << ",";
			}
			outfile << "第" << t + 1 << "次迭代后的最优解为:";
			for (int j = 0; j < citycount; j++)
			{
				if (j == 0)
					outfile << "f(" << xbest[j] << ",";
				else if (j == citycount - 1)
					outfile << xbest[j] << ")=" << bestdisvalue << endl;
				else
					outfile << xbest[j] << ",";
			}
		}
		outfile << "迭代结束后的最优解如下:" << endl;
		for (int i = 0; i < citycount; i++)
		{
			if (i == 0)outfile << "f(" << xbest[i] << ",";
			else if (i == citycount - 1) outfile << xbest[i] << ")=" << bestdisvalue << endl;
			else outfile << xbest[i] << ",";
		}
		outfile << "迭代结束后的禁忌表如下:" << endl;
		for (int i = 0; i < currentjinjicount; i++)
		{
			for (int j = 0; j < citycount; j++)
			{
				if (j == 0)outfile << "f(" << TabuTable[i][j] << ",";
				else if (j == citycount - 1) outfile << TabuTable[i][j] << ") =  " << Evaluate(TabuTable[i]) << endl;
				else outfile << TabuTable[i][j] << ",";
			}
		}
		outfile.close();
	}
};
int main()
{
	system("mode con cols=200");
	system("color fc");
	TS ts;
	ts.TS_TSP(8, 20, 100, "E:\\计算智能代码\\TS_TSP\\TS_TSP\\bayg29.tsp");
	system("pause");
	return 0;
}



版权声明:本文为jing_zhong原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。