模拟退火算法(SA)求解TSP 问题(C语言实现)
这篇文章是之前写的智能算法(遗传算法(GA)、粒子群算法(PSO))的补充。其实代码我老早之前就写完了,今天恰好重新翻到了,就拿出来给大家分享一下,也当是回顾与总结了。
首先介绍一下模拟退火算法(SA)。模拟退火算法(simulated annealing,SA)算法最早是由Metropolis等人提出的。其出发点是基于物理中固体物质的退火过程与一般组合优化问题之间的相似性。模拟退火算法是一种通用的优化算法,其物理退火过程由以下三部分组成:
(1)加温过程
(2)等温过程
(3)冷却过程
其中加温过程对应算法设定的初始温度,等温过程对应算法的Metropolis抽样过程,冷却过程对应控制参数的下降。这里能量的变化就是目标函数,要得到的最优解就是能量最低状态。Metropolis准则是SA算法收敛于全局最优解的关键所在,Metropolis准则以一定的概率接受恶化解,这样就使得算法可以跳离局部最优解的陷阱。
模拟退火算法为求解传统方法难以处理的TSP问题提供了一个有效的途径和通用的处理框架,并逐渐发展成为一种迭代自适应启发式概率搜索算法。模拟退火算法可以用于求解不同的非线性问题,对于不可微甚至不连续函数的优化,能以较大概率求得全局最优解,该算法还具有较强的鲁棒性、全局收敛性、隐含并行性以及广泛的适应性,对目标函数以及约束函数没有任何要求。
SA 算法实现的步骤如下:(下面以最小化问题为例)
(1)初始化:取温度T0足够大,令T = T0,取任意解S1,确定每个T时 的迭代次数,即 Metropolis链长L。
(2)对当前温度T和k=1,2,3,...,L,重复步骤(3)~(6)
(3)对当前解S1随机产生一个扰动得到一个新解 S2.
(4) 计算S2的增量df = f(S2) - f(S1),其中f(S1)为S1的代价函数。
(5)若df < 0,接受S2作为新的当前解,即S1 = S2;否则S2的接受概率为 exp(-df/T),即随机产生(0,1)上的均匀分布的随机数rand,若 exp(-df/T)>rand
,则接受S2作为新的当前解,S1 = S2;否则保留当前解。
(6)如果满足最终的终止条件,Stop,则输出当前解S1作为最优解,结束程序。终止条件Stop通常为:在连续若干个Metropolis链中新解S2都没有被接受时终止算法,或者是设定结束温度。否则按衰减函数衰减T后返回(2)
以上的步骤称之为Metropolis过程。逐步降低控制温度,重复Metropolis过程,直至满足结束准则Stop求出最优解。可以看出SA整体的步骤相比GA以及PSO还是简单了很多了,而且亲测效果还不错,所以属于性价比较高的算法。关键的步骤在第(6)步。
不废话了,直接上代码吧。TSP的数据和之前的数据一样,使用C语言实现。代码如下:
/*
* 使用模拟退火算法(SA)求解TSP问题(以中国TSP问题为例)
* 参考自《Matlab 智能算法30个案例分析》
* 模拟退火的原理这里略去,可以参考上书或者相关论文
* update: 16/12/11
* author:lyrichu
* email:919987476@qq.com
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#include<math.h>
#define T0 50000.0 // 初始温度
#define T_end (1e-8)
#define q 0.98 // 退火系数
#define L 1000 // 每个温度时的迭代次数,即链长
#define N 31 // 城市数量
int city_list[N]; // 用于存放一个解
double city_pos[N][] = {{,},{,},{,},{,},{,},{,},{,},{,},{,},
{,},{,},{,},{,},{,},{,},{,},{,},{,},{,},{,},{,},
{,},{,},{,},{,},{,},{,},{,},{,},{,},{,}}; // 中国31个城市坐标
//函数声明
double distance(double *,double *); // 计算两个城市距离
double path_len(int *); // 计算路径长度
void init(); //初始化函数
void create_new(); // 产生新解
// 距离函数
double distance(double * city1,double * city2)
{
double x1 = *city1;
double y1 = *(city1+);
double x2 = *(city2);
double y2 = *(city2+);
double dis = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
return dis;
} // 计算路径长度
double path_len(int * arr)
{
double path = ; // 初始化路径长度
int index = *arr; // 定位到第一个数字(城市序号)
for(int i=;i<N-;i++)
{
int index1 = *(arr+i);
int index2 = *(arr+i+);
double dis = distance(city_pos[index1-],city_pos[index2-]);
path += dis;
}
int last_index = *(arr+N-); // 最后一个城市序号
int first_index = *arr; // 第一个城市序号
double last_dis = distance(city_pos[last_index-],city_pos[first_index-]);
path = path + last_dis;
return path; // 返回总的路径长度
} // 初始化函数
void init()
{
for(int i=;i<N;i++)
city_list[i] = i+; // 初始化一个解
} // 产生一个新解
// 此处采用随机交叉两个位置的方式产生新的解
void create_new()
{
double r1 = ((double)rand())/(RAND_MAX+1.0);
double r2 = ((double)rand())/(RAND_MAX+1.0);
int pos1 = (int)(N*r1); //第一个交叉点的位置
int pos2 = (int)(N*r2);
int temp = city_list[pos1];
city_list[pos1] = city_list[pos2];
city_list[pos2] = temp; // 交换两个点
} // 主函数
int main(void)
{
srand((unsigned)time(NULL)); //初始化随机数种子
time_t start,finish;
start = clock(); // 程序运行开始计时
double T;
int count = ; // 记录降温次数
T = T0; //初始温度
init(); //初始化一个解
int city_list_copy[N]; // 用于保存原始解
double f1,f2,df; //f1为初始解目标函数值,f2为新解目标函数值,df为二者差值
double r; // 0-1之间的随机数,用来决定是否接受新解
while(T > T_end) // 当温度低于结束温度时,退火结束
{
for(int i=;i<L;i++)
{
memcpy(city_list_copy,city_list,N*sizeof(int)); // 复制数组
create_new(); // 产生新解
f1 = path_len(city_list_copy);
f2 = path_len(city_list);
df = f2 - f1;
// 以下是Metropolis准则
if(df >= )
{
r = ((double)rand())/(RAND_MAX);
if(exp(-df/T) <= r) // 保留原来的解
{
memcpy(city_list,city_list_copy,N*sizeof(int));
}
}
}
T *= q; // 降温
count++;
}
finish = clock(); // 退火过程结束
double duration = ((double)(finish-start))/CLOCKS_PER_SEC; // 计算时间
printf("采用模拟退火算法,初始温度T0=%.2f,降温系数q=%.2f,每个温度迭代%d次,共降温%d次,得到的TSP最优路径为:\n",T0,q,L,count);
for(int i=;i<N-;i++) // 输出最优路径
{
printf("%d--->",city_list[i]);
}
printf("%d\n",city_list[N-]);
double len = path_len(city_list); // 最优路径长度
printf("最优路径长度为:%lf\n",len);
printf("程序运行耗时:%lf秒.\n",duration);
return ;
}
运行结果截图如下:
注:如果使用gcc编译报错,可能需要加上 -std=c99选项以及在末尾加上 -lm(链接math库)。
模拟退火算法(SA)求解TSP 问题(C语言实现)的更多相关文章
- 模拟退火算法SA原理及python、java、php、c++语言代码实现TSP旅行商问题,智能优化算法,随机寻优算法,全局最短路径
模拟退火算法SA原理及python.java.php.c++语言代码实现TSP旅行商问题,智能优化算法,随机寻优算法,全局最短路径 模拟退火算法(Simulated Annealing,SA)最早的思 ...
- 【智能算法】用模拟退火(SA, Simulated Annealing)算法解决旅行商问题 (TSP, Traveling Salesman Problem)
喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 文章声明 此文章部分资料和代码整合自网上,来源太多已经无法查明出处,如侵犯您的权利,请联系我删除. 01 什么是旅行商问题(TS ...
- OI骗分神器——模拟退火算法
前言&&为什么要学模拟退火 最近一下子学了一大堆省选算法,所以搞一个愉快一点的东西来让娱乐一下 其实是为了骗到更多的分,然后证明自己的RP. 说实话模拟退火是一个集物理与IT多方面知识 ...
- 遗传算法的C语言实现(二)-----以求解TSP问题为例
上一次我们使用遗传算法求解了一个较为复杂的多元非线性函数的极值问题,也基本了解了遗传算法的实现基本步骤.这一次,我再以经典的TSP问题为例,更加深入地说明遗传算法中选择.交叉.变异等核心步骤的实现.而 ...
- 【优化算法】变邻域搜索算法(VNS)求解TSP(附C++详细代码及注释)
00 前言 上次变邻域搜索的推文发出来以后,看过的小伙伴纷纷叫好.小编大受鼓舞,连夜赶工,总算是完成了手头上的一份关于变邻域搜索算法解TSP问题的代码.今天,就在此给大家双手奉上啦,希望大家能ENJO ...
- 基于粒子群算法求解求解TSP问题(JAVA)
一.TSP问题 TSP问题(Travelling Salesman Problem)即旅行商问题,又译为旅行推销员问题.货郎担问题,是数学领域中著名问题之一.假设有一个旅行商人要拜访n个城市,他必须选 ...
- 基于贪心算法求解TSP问题(JAVA)
概述 前段时间在搞贪心算法,为了举例,故拿TSP来开刀,写了段求解算法代码以便有需之人,注意代码考虑可读性从最容易理解角度写,没有优化,有需要可以自行优化! 详细 代码下载:http://www.de ...
- 模拟退火算法 R语言
0 引言 模拟退火算法是用来解决TSP问题被提出的,用于组合优化. 1 原理 一种通用的概率算法,用来在一个打的搜索空间内寻找命题的最优解.它的原理就是通过迭代更新当前值来得到最优解.模拟退火通常使用 ...
- 基于爬山算法求解TSP问题(JAVA)
一.TSP问题 TSP问题(Travelling Salesman Problem)即旅行商问题,又译为旅行推销员问题.货郎担问题,是数学领域中著名问题之一.假设有一个旅行商人要拜访n个城市,他必须选 ...
随机推荐
- 每天一个linux命令(33)--df命令
周末是学习的好时光. 每天一个Linux命令,接下来是磁盘存储相关的,df, du命令 Linux中 df 命令的功能是用来检查Linux 服务器的文件系统的磁盘空间占用情况.可以利用该命令来获取硬 ...
- 使用jQuery快速高效制作网页特效-----------------------------之jQuery事件与动画
1.基础事件 分为三个事件 1.1 window事件 所谓window事件,就是当用户执行某些会影响浏览器的操作时,而触发的事件. 1.2 鼠标事件 鼠标事件顾名思义就是当用户在文档上移动或单击鼠标时 ...
- 大型ERP系统在线体验
ERP简单说明: AIO7构建了基于SOA三层架构的管理软件平台.客户通过网络即可得到ERP服务,不用安装服务器.不用建立数据中心.不用安装软件.无需专业IT支持,任何上网设备就可以使用高性能.功能集 ...
- Oracle Developer Data Modeler项目实践 (转)
http://www.Oracle.com/webfolder/technetwork/tutorials/obe/db/sqldevdm/r30/datamodel2moddm/datamodel2 ...
- APUE学习心得
APUE学习心得 Chapter 3 IO 3.2 文件描述符 文件描述符是一个非负整数.当打开 一个现存文件或创建一个新文件时,内核向进程返回一个文件描述符.0 标准输入,1 标准输出, 2 标准错 ...
- File类和时间类的两道综合练习
练习1: 获取指定目录下(包含子目录)所有的某一种类型的文件 分析: 1.指定路径并获取其下的文件对象 2.要判断给定的目录是否为空 3.要判断给定路径下获取的目录是否为空 4.判断是否是某种文件 5 ...
- 一个小时学会jQuery
前一段时间录了一套关于jQuery的视频分享给大家,可以在下载区下载到,本来想配合文字一起的,后面发现视频+帮助文档也是非常好的学习方法. 一.jQuery简介与第一个jQuery程序 1.1.jQu ...
- laravel 简单的上传图片
/** * laravel 简单的上传图片* @param Request $request* @return View*/public function upload(Request $reque ...
- React Native 之 项目实战(一)
前言 本文有配套视频,可以酌情观看. 文中内容因各人理解不同,可能会有所偏差,欢迎朋友们联系我. 文中所有内容仅供学习交流之用,不可用于商业用途,如因此引起的相关法律法规责任,与我无关. 如文中内容对 ...
- Java中实现短信发送
最近跟着做公司的项目偶然接触到的,顺势把这个给记录下来,给自己梳理一下. 采用引入第三方工具的方式,网上查了半天,发现简单的实现方式便是注册一个中国网建的账号,新建账号的时候会附带赠几条免费短信,彩信 ...