这篇文章是之前写的智能算法(遗传算法(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语言实现)的更多相关文章

  1. 模拟退火算法SA原理及python、java、php、c++语言代码实现TSP旅行商问题,智能优化算法,随机寻优算法,全局最短路径

    模拟退火算法SA原理及python.java.php.c++语言代码实现TSP旅行商问题,智能优化算法,随机寻优算法,全局最短路径 模拟退火算法(Simulated Annealing,SA)最早的思 ...

  2. 【智能算法】用模拟退火(SA, Simulated Annealing)算法解决旅行商问题 (TSP, Traveling Salesman Problem)

    喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 文章声明 此文章部分资料和代码整合自网上,来源太多已经无法查明出处,如侵犯您的权利,请联系我删除. 01 什么是旅行商问题(TS ...

  3. OI骗分神器——模拟退火算法

    前言&&为什么要学模拟退火 最近一下子学了一大堆省选算法,所以搞一个愉快一点的东西来让娱乐一下 其实是为了骗到更多的分,然后证明自己的RP. 说实话模拟退火是一个集物理与IT多方面知识 ...

  4. 遗传算法的C语言实现(二)-----以求解TSP问题为例

    上一次我们使用遗传算法求解了一个较为复杂的多元非线性函数的极值问题,也基本了解了遗传算法的实现基本步骤.这一次,我再以经典的TSP问题为例,更加深入地说明遗传算法中选择.交叉.变异等核心步骤的实现.而 ...

  5. 【优化算法】变邻域搜索算法(VNS)求解TSP(附C++详细代码及注释)

    00 前言 上次变邻域搜索的推文发出来以后,看过的小伙伴纷纷叫好.小编大受鼓舞,连夜赶工,总算是完成了手头上的一份关于变邻域搜索算法解TSP问题的代码.今天,就在此给大家双手奉上啦,希望大家能ENJO ...

  6. 基于粒子群算法求解求解TSP问题(JAVA)

    一.TSP问题 TSP问题(Travelling Salesman Problem)即旅行商问题,又译为旅行推销员问题.货郎担问题,是数学领域中著名问题之一.假设有一个旅行商人要拜访n个城市,他必须选 ...

  7. 基于贪心算法求解TSP问题(JAVA)

    概述 前段时间在搞贪心算法,为了举例,故拿TSP来开刀,写了段求解算法代码以便有需之人,注意代码考虑可读性从最容易理解角度写,没有优化,有需要可以自行优化! 详细 代码下载:http://www.de ...

  8. 模拟退火算法 R语言

    0 引言 模拟退火算法是用来解决TSP问题被提出的,用于组合优化. 1 原理 一种通用的概率算法,用来在一个打的搜索空间内寻找命题的最优解.它的原理就是通过迭代更新当前值来得到最优解.模拟退火通常使用 ...

  9. 基于爬山算法求解TSP问题(JAVA)

    一.TSP问题 TSP问题(Travelling Salesman Problem)即旅行商问题,又译为旅行推销员问题.货郎担问题,是数学领域中著名问题之一.假设有一个旅行商人要拜访n个城市,他必须选 ...

随机推荐

  1. 2017-2-19 C#基础 基本数据类型的转换,转义字符,常量

    1.基本数据类型的转换分两种:自动转换(隐式转换)和强制转换(显式转换).自动转换是从只类型转换到引用类型.强制转换是最长用的,是从引用类型转换到值类型或者从浮点型转换到整形.强制转换主要有三种形式: ...

  2. iOS 快速集成启动页广告

    前言 由于项目中要用到启动页广告,所以做了简单的研究,同时借鉴网易新闻和蘑菇街的交互写了一个简单的demo,现在写出来供大家参考,可能由于个人局限会有一些bug和不完善的地方,也希望大家能够友善提醒和 ...

  3. 【排序算法】希尔排序算法 Java实现

    希尔排序算法是按其设计者希尔(Donald Shell)的名字命名,该算法由1959年公布,是插入排序的一种更高效的改进版本. 希尔排序是基于插入排序的以下两点性质而提出改进方法的: 插入排序在对几乎 ...

  4. jiayuan

    8.2=http://files.cnblogs.com/files/bqh10086/jiayuan8.2pack.zip

  5. smarty模板基础1

    smarty模板的作用可以让前端和后端分离(也就是前端的显示页面和后端的php代码). smarty模板的核心是一个类,下载好的模板中有这么几个重要的文件夹 (1)libs核心文件夹(2)int.in ...

  6. 开始了大概三四天的Rails学习之路

    最近因为一位极光推送朋友,我开始了大概三四天的Rails学习之路,最终达到的水平是可以比较轻松地做出大部分功能,然后自我感觉可以自如地按照Rails的设计思想去思考.由于编程的日益流行,我结识了越来越 ...

  7. Linux下修改系统时区

    使用 /etc/localtime 文件修改时区 先查看一下当前的时区,下面这个例子中使用 UTC 即世界统一标准时区.假设你可能需要改为美国西部标准时间,即太平洋时间. # date Thu Aug ...

  8. web计时机制——performance对象

    前面的话 页面性能一直都是Web开发人员最关注的领域.但在实际应用中,度量页面性能的指标,是提高代码复杂程度和巧妙地使用javascript的Date对象.Web Timing API改变了这个局面, ...

  9. Linux i2c子系统(四) _从i2c-s3c24xx.c看i2c控制器驱动的编写

    "./drivers/i2c/busses/i2c-s3c2410.c"是3.14.0内核中三星SoC的i2c控制器驱动程序, 本文试图通过对这个程序的分析, 剥离繁复的细节, 总 ...

  10. Caffe学习系列(一)Ubuntu16.04下搭建编译Caffe环境,并运行MNIST示例(仅CPU)

    前言: 正文: 1.安装必要依赖包: sudo apt-get install libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev l ...