模拟退火算法求解TSP问题(C++实现)

在机器学习和深度学习中经常需要求解一个最优值,但是很多函数得到的仅仅是局部最优解,在求解全局最优解时,则需要用到一些算法,这里我用模拟退火算法来进行最优解的求解。这个原理网上教程应该很多,我就不赘述了,具体影响到算法解的结果有很多因素,比如初始温度值的设定,退火的速率以及随机数的随机性,都会影响到解的结果,这里我用C++实现了一遍,希望对大家有所帮助:

#include<iostream>
#include<cmath>
#include<cstdlib>
#include<vector>
#include<ctime>

#define T_MAX 1e+6
#define T_MIN 50
#define ITER_TIMES 50
#define ALPHA 0.98

using namespace std;

vector<int>Value_Input;
vector<int>Value_Output;

void Input_Data()
{
	int x[29] = { 11501760,6301660,402090,7501100,7502030,10302070,1650650,
		14901630,7902260,7101310,8400550,11702300,9701340,5100700,
		7500900,12801200,2300590,4600860,10400950,5901390,8301770,4900500,
		18401240,12601500,12800790,4902130,14601420,12601910,3601980};	//对坐标进行编码,利于计算。
	for (unsigned int i = 0; i < 29; i++)
	{
		Value_Input.push_back(x[i]);
	}
}

static float Distance()
{
	int x, y;	//解码后的x,y
	vector<int>x_state;	//将解码后的x储存起来
	vector<int>y_state;	//将解码后的y储存起来
	int Distance_Of_All = 0;	//总距离
	int square_x;
	int square_y;
	float Distance_Each;
	/*将输入解码后得到输出x,y*/
	for (size_t i = 0; i < Value_Input.size(); i++)
	{
		x = Value_Input[i] / 10000;
		y = Value_Input[i] - 10000 * x;
		x_state.push_back(x);
		y_state.push_back(y);
	}
	/*分别获取x,y方向的总距离*/
	for (size_t i = 0; i < x_state.size() - 1; i++)
	{
		square_x = pow((x_state[i] - x_state[i + 1]), 2);
		square_y = pow((x_state[i] - x_state[i + 1]), 2);
		Distance_Each = powf((square_x + square_y), 0.5);
		Distance_Of_All += Distance_Each;
	}
	/*计算终点与起点的距离*/
	square_x += pow((x_state[0] - x_state[x_state.size() - 1]), 2);
	square_y += pow((y_state[0] - y_state[y_state.size() - 1]), 2);
	Distance_Each = powf((square_x + square_y), 0.5);
	Distance_Of_All += Distance_Each;
	return Distance_Of_All;
}

void Simulated_Annealing()
{
	int a, b;	//生成两个随机数
	float p;	//随机概率(与Metropolis准则得到的概率比较)
	float Metropolis;
	float temputure = T_MAX;	//当前温度
	float E_FIRST, E_SECOND;	//E_FIRST为原来的总能量,E_SECOND为变化后的能量
	srand(time(NULL));
	while (temputure >= T_MIN)
	{
		for (int i = 0; i < ITER_TIMES; i++)
		{
			a = rand() % 29;	//生成第一个随机数
			b = rand() % 29;	//生成第二个随机数
			while (a!=b)
			{
				E_FIRST = Distance();	//求解初始距离
				swap(Value_Input[a], Value_Input[b]);	//交换两个数
				E_SECOND = Distance();	//求解第二个距离
				/*如果得到更优的解则替换,不是的话进行下一步*/
				if (E_FIRST >= E_SECOND)
				{
					break;
				}
				/*生成随机概率p与Metropolis值进行比较*/
				p = rand() % 2;
				Metropolis = exp2f((E_FIRST - E_SECOND) / temputure);
				if (p >= Metropolis)
				{
					Value_Output.push_back(E_SECOND);
					break;
				}
				/*如果不同意的话取消交换*/
				swap(Value_Input[a], Value_Input[b]);
			}
		}
		temputure *= ALPHA;	//温度迭代(退火)
	}

}

void outputVector()
{
	int x, y;
	float distance;
	for (size_t i = 0; i < Value_Input.size(); i++)
	{
		x = Value_Input[i] / 10000;	//解码得到x
		y = Value_Input[i] - 10000 * x;	//解码得到y
		cout << "x = " << x << "y =" << y << endl;
	}
	distance = Distance();	//输出距离
	cout << "距离为" << distance << endl;
}

int main()
{
	Input_Data();	//这里可以自己输入TSP坐标
	Simulated_Annealing();	//模拟退火算法
	outputVector();	//输出最终结果
	return 0;
}

结果输出为:

x = 1150,y =1760
x = 360,y =1980
x = 490,y =500
x = 750,y =2030
x = 1280,y =790
x = 1260,y =1500
x = 750,y =1100
x = 630,y =1660
x = 710,y =1310
x = 1040,y =950
x = 970,y =1340
x = 40,y =2090
x = 510,y =700
x = 830,y =1770
x = 840,y =550
x = 1490,y =1630
x = 165,y =650
x = 750,y =900
x = 1030,y =2070
x = 1460,y =1420
x = 790,y =2260
x = 460,y =860
x = 1260,y =1910
x = 590,y =1390
x = 1840,y =1240
x = 1280,y =1200
x = 490,y =2130
x = 230,y =590
x = 1170,y =2300
距离为21374

但是最终输出并不稳定,需要与迭代过程中的值进行比较,得到最终的最优规划。因此加入修正项后的值已经接近最优。最终的值为13212.

sort(Value_Output.begin(), Value_Output.end());
	distance = Distance();	//迭代完成后的距离
	if (Value_Output[0]<=distance)
	{
		cout << "距离为" << Value_Output[0] << endl;
	}
	else
	{
		cout << "距离为" << distance << endl;
	}

这里是对结果的修正。
接下来是输出:

x = 510,y =700
x = 1260,y =1500
x = 1490,y =1630
x = 1280,y =1200
x = 750,y =1100
x = 710,y =1310
x = 1460,y =1420
x = 830,y =1770
x = 230,y =590
x = 1030,y =2070
x = 40,y =2090
x = 750,y =900
x = 460,y =860
x = 1150,y =1760
x = 630,y =1660
x = 1280,y =790
x = 750,y =2030
x = 1040,y =950
x = 840,y =550
x = 790,y =2260
x = 490,y =2130
x = 590,y =1390
x = 1170,y =2300
x = 490,y =500
x = 970,y =1340
x = 165,y =650
x = 1260,y =1910
x = 1840,y =1240
x = 360,y =1980
距离为13212

这就是模拟退火算法的大概流程了,想继续研究精度的可以继续研究。如果有错的地方也请大家批评指正

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值