模拟退火算法(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个城市,他必须选 ...
随机推荐
- 存储过程与SQL语句如何选择
58到家数据库30条军规,有一条是“禁止使用存储过程.视图.触发器.Event”, 高并发大数据的互联网业务,架构设计思路是“解放数据库CPU,将计算转移到服务层”, 并发量大的情况下,这些功能很可能 ...
- webstorm 编辑器破解 (麻麻再也不用担心过期了)
先去官网下载webstorm2016.1.3版本(目前只知道2016.1这个版本可以永久破解,不会过期) 再下载webstorm2016.1的破解补丁 将下载好的破解补丁解压,会有一个Jetbrain ...
- cookie跨域和js跨域问题
js跨域:主机名,协议,端口号只要有任何一个不同,就不能成立
- 了解 : angular $rootScope 在 ui-view
在view 的element 可以直接调用 <p>{{$stateParams.xx}}</p> 要让xx有资料必须注入 app.run["$rootScope&qu ...
- Javaweb之Jsp
1. JSP是什么? JSP全称Java Server Pages,是一种动态网页开发技术.它使用JSP标签在HTML网页中插入Java代码.标签通常以<%开头以%>结束. 2. JSP带 ...
- (五)CSS和JavaScript基础
DHTML :制作动态HTML页面的技术 DHTML=HTML+层叠样式表CSS+脚本语言javascript 一.CSS 1.1 CSS样式的分类: 行内样式:只影响一行,其他相同标签也不影响.如下 ...
- java-信息安全(一)-BASE64,MD5,SHA,HMAC
概述 信息安全基本概念: BASE64 编码格式 MD5(Message Digest algorithm 5,信息摘要算法) SHA(Secure Hash Algorithm,安全散列算法) HM ...
- Omi v1.0震撼发布 - 令人窒息的Web组件化框架
原文链接--https://github.com/AlloyTeam/omi 写在前面 Omi框架经过几十个版本的迭代,越来越简便易用和强大. 经过周末的连续通宵加班加点,Omi v1.0版本终于问世 ...
- Linux(CentOS6.7) 安装MySql5.7数据库
linux(CentOS6.7) 环境Mysql 5.7.17安装教程分享给大家,供大家参考,具体内容如下: 1系统约定安装文件下载目录:/data/softwareMysql目录安装位置:/usr/ ...
- spdlog源码阅读 (3): log_msg和BasicWriter
4. log_msg和它的打手BasicWriter 在spdlog源码阅读 (2): sinks的创建和使用中,提到log_msg提供了存储日志的功能.那么到底在spdlog中它是怎么 起到这个作用 ...