算法:模拟退火(基于c++程序)
一 什么是模拟退火算法?
- 所谓退火,其实是金属冶炼的一个名词.比如加工一把刀,我们通常是把材料加工到很高的一个温度,加以锤炼.之后慢慢的将温度降下来,如果我们降温的控制比较好的话,那么金属里面的原子就更加偏向于形成能量比较低的状态,如果一个粒子能量很低,他的稳定性会更强,不易受到损坏.刀会更锋利,韧性更足.
- 当一个函数问题比较复杂的时候,无法通过直接微分求出.因为受到退火的启发,我们就可以通过这个算法求出一个复杂函数的极值问题.
二 模拟退火算法原理(策略)

比如先看第一种情况(粉色),X(n)变化到X(n+1)时,可以是温度(能量)下降的,这个是百分百是允许的,因为我的目的是让他下降的(好像是废话哎…).但这就带来了一个问题,X(n+1)可能会陷入一个局部最优解,不能正确的找到全局最优.
因此,我们必须允许一定的概率产生第二种情况(红色)来跳出局部最优解.这个概率与温度(能量)有很大的关系,温度越高,往上蹦的概率也越大,蹦得高度也越大,这样它有可能跳出局部最优解,从而陷入更深的坑里面去(因此就可能是全局最优啦).因此蹦进小坑可能会出来,但进入大坑再出来的可能性就很小,通过这样迭代,就可以找到全局最优解.
因此,初始温度越高,退火过程越慢,越容易得到全局最优,当然这样花费的时间越长,这也是必须付出的代价.
三 公式

这下来看看公式,当从 X(n) 变化到 X(n+1) 时,能量 E 如果是下降的,让它产生这个概率为1.当从 X(n) 变化到 X(n+1) 时,能量 E 如果是 上升的,这个概率是 exp(-(E(new)-E(old))/T) .因此温度越大 ,概率越高.温度越低,往上蹦的概率越低.
模拟退火一般有两个循环过程来组成:
在外循环里面,每一次迭代温度都会改变。
T(n)= λT(n-1) ,其中 λ 是一个小于1的数,一 般取值在0.8-0.99之间,使得对每一温度,都有足够的次数去尝试.收敛速度比较慢.
在内循环里面,以一定规则在当前状态附近产生新的状态 x(n) 产生 x’(n) ,计算 f(x(n)) 和 f(x’(n)) . 得到
Δf=f(x’(n))-f(x(n)) .
如果 Δf<0 , 说明 x’(n) 好于 x(n) ,因此 x(n+1)=x’(n) . 如果 Δf>0, 计算 p , 产生一个随机数 α ,若 p>α .则接受 x’(n) 为 下一个状态值 , x(n+1)=x’(n) . 否则拒绝 x’(n) . x(n+1)=x(n) .
根据内循环终止准则,检查是否达到热平衡。按照公式调整温度,根据外循环终止准则检查退火算法是否收敛。 外循环终止的准则也可以设置为固定的迭代次数,达到该次数以后系统即停止计算。
四 代码(旅行商问题)
//模拟退火
#include<iostream>
#include<string.h>
#include<time.h>
#include<math.h>
#define T_start 100000 //初始温度
#define T_end (1e-9)
#define q 0.95 //退火系数
#define L 1000 //每个温度时的迭代次数
#define N 52//数组的行数
int city_l[N];//用于存放一个解
double city_p[N][2] = { { 565,575 },{ 25,185 },{ 345,750 },{ 945,685 },{ 845,655 },//每个城市的坐标
{ 880,660 },{ 25,230 },{ 525,1000 },{ 580,1175 },{ 650,1130 },{ 1605,620 },
{ 1220,580 },{ 1465,200 },{ 1530,5 },{ 845,680 },{ 725,370 },{ 145,665 },
{ 415,635 },{ 510,875 },{ 560,365 },{ 300,465 },{ 520,585 },{ 480,415 },
{ 835,625 },{ 975,580 },{ 1215,245 },{ 1320,315 },{ 1250,400 },{ 660,180 },
{ 410,250 },{ 420,555 },{ 575,665 },{ 1150,1160 },{ 700,580 },{ 685,595 },
{ 685,610 },{ 770,610 },{ 795,645 },{ 720,635 },{ 760,650 },{ 475,960 },
{ 95,260 },{ 875,920 },{ 700,500 },{ 555,815 },{ 830,485 },{ 1170,65 },
{ 830,610 },{ 605,625 },{ 595,360 },{ 1340,725 },{ 1740,245 } };
//计算两座城市距离
double distance(double* city1, double* city2) {
double x1 = *city1;
double y1 = *(city1 + 1);
double x2 = *city2;
double y2 = *(city2 + 1);
double dis = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
return dis;
}
//计算从第一个到最后一个的路径长度
double path_len(int* arr) {
double path = 0;
int index = *arr;//定位至第一个城市
for (int i = 0; i < N - 1; i++) {
int index1 = *(arr + i); int index2 = *(arr + i + 1);
double dis = distance(city_p[index1 - 1], city_p[index2 - 1]);
path += dis;
}
int last_index = *(arr + N - 1);//最后一个城市序号
int first_index = *arr;//第一个城市序号
double last_dis = distance(city_p[last_index - 1], city_p[first_index - 1]);
path += last_dis;
return path;
} //初始化函数
void init() {
for (int i = 0; i < N; i++)
city_l[i] = i + 1;//初始化一个解
}
//产生一个新解,采用随机交叉两个位置的方式产生新的解
void create_new() {
double r1 = ((double)rand()) /(double)(RAND_MAX + 1.0);
double r2 = ((double)rand()) / (double)(RAND_MAX + 1.0);
int pos1 = (int)(N*r1);
int pos2 = (int)(N*r2);
int temp = city_l[pos1];
city_l[pos1] = city_l[pos2];
city_l[pos2] = temp;
}
int main() {
srand((unsigned)time(NULL));//初始化随机数种子
time_t start, finish;//计算算法持续时间
start = clock();
double T = T_start;
int count = 0;//记录降温次数
init();//随便初始化一个值
int city_l_copy[N];//用于保存原始解
double f1, f2, df;
double r;
while (T > T_end) {//温度低于结束温度时,退火结束
for (int i = 0; i < L; i++) //迭代L次
{
//复制数组
memcpy(city_l_copy, city_l, N * sizeof(int));
create_new();//产生新解
f1 = path_len(city_l_copy);
f2 = path_len(city_l);
df = f2 - f1;
/*
如果df<0,那么结果取最小的就是city_1,不做任何。
如果df>=0,那么
*/
if (df <= 0) {
r = ((double)rand()) / (RAND_MAX);
if (exp(-df / T) >=r) {//保留原解
memcpy(city_l, city_l_copy, N * sizeof(int));
}
}
}
T *= q;//降温0
count++;
}
finish = clock();
double duration = ((double)(finish - start)) / CLOCKS_PER_SEC;//持续时间
double len = path_len(city_l);
printf("初始温度 T=%d,降温系数 q=%.2f,每个温度迭代%d 次\n", T_start, q, L, count);
printf("最优路径长度为:%lf\n程序耗时: %lf\n最优路径为:\n", len, duration);
for (int i = 0; i < N - 1; i++) {
printf("%d->", city_l[i]);
}
printf("%d\n", city_l[N - 1]);
return 0;
}
。
五 应用
本算法多应用在神经网络的研究中,其他类似的算法包括蚁群算法,遗传算法等将在以后博客里再讲述.
算法:模拟退火(基于c++程序)的更多相关文章
- 最小生成树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind
最小支撑树树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind 最小支撑树树 前几节中介绍的算法都是针对无权图的,本节将介绍带权图的最小 ...
- [转载] 使用C/C++语言编写基于DSP程序的注意事项
原文地址:『转』使用C/C++语言编写基于DSP程序的注意事项作者:skysmile 1.不影响执行速度的情况下,可以使用c或c/c++语言提供的函数库,也可以自己设计函数,这样更易于使用“裁缝师 ...
- kmeans算法并行化的mpi程序
用c语言写了kmeans算法的串行程序,再用mpi来写并行版的,貌似参照着串行版来写并行版,效果不是很赏心悦目~ 并行化思路: 使用主从模式.由一个节点充当主节点负责数据的划分与分配,其他节点完成本地 ...
- Breaseman算法绘制圆形|中点算法绘制圆形_程序片段
Breaseman算法绘制圆形|中点算法绘制圆形_程序片段 1. Breaseman算法绘制圆形程序 由于算法的特殊性,限制绘制第一象限部分,其他部分通过旋转绘制. void CCGProjectWo ...
- 2维FFT算法实现——基于GPU的基2快速二维傅里叶变换
上篇讲述了一维FFT的GPU实现(FFT算法实现——基于GPU的基2快速傅里叶变换),后来我又由于需要做了一下二维FFT,大概思路如下. 首先看的肯定是公式: 如上面公式所描述的,2维FFT只需要拆分 ...
- Net Core基于TopShelf程序运行于服务模式
目录 Net Core基于TopShelf程序运行于服务模式 1 背景 2 优势 2.1 服务模式可设置重启条件 2.2 避免误操作 3.使用 3.1 GUI方式安装Topshelf包 4 配置 5 ...
- Canny边缘检测算法(基于OpenCV的Java实现)
目录 Canny边缘检测算法(基于OpenCV的Java实现) 绪论 Canny边缘检测算法的发展历史 Canny边缘检测算法的处理流程 用高斯滤波器平滑图像 彩色RGB图像转换为灰度图像 一维,二维 ...
- 基于小程序请求接口 wx.request 封装的类 axios 请求
基于小程序请求接口 wx.request 封装的类 axios 请求 Introduction wx.request 的配置.axios 的调用方式 源码戳我 feature 支持 wx.reques ...
- 基于小程序云Serverless开发微信小程序
本文主要以使用小程序云Serverless服务开发一个记事本微信小程序为例介绍如何使用小程序云Serverless开发微信小程序.记事本小程序的开发涉及到云函数调用.云数据库存储.图片存储等功能,较好 ...
- canvas菜鸟基于小程序实现图案在线定制功能
前言 最近收到一个这样的需求,要求做一个基于 vue 和 element-ui 的通用后台框架页,具体要求如下: 要求通用性高,需要在后期四十多个子项目中使用,所以大部分地方都做成可配置的. 要求做成 ...
随机推荐
- EPX-Studio操作多线程的方法
procedure TF1167908962.Button1Click(Sender: TObject); begin ThIndex := ; EPXThread1.StartThread; EPX ...
- K:剑指offer-56 题解 谁说数字电路的知识不能用到算法中?从次数统计到数字电路公式推导,一文包你全懂
前言: 本题解整理了一位大佬在leetcode中的代码的方法,该博文致力于让所有人都能够能够看懂该方法.为此,本题解将从统计数字出现次数的解题方式开始讲起,再推导出逐位统计的解题方式,期望以循序渐进的 ...
- CF1326A Bad Ugly Numbers 题解
原题链接 简要题意: 构造一个长为 \(n\) 的数,使得每位均不为 \(0\),且 \(n\) 不被它的各位数字整除. 比方说, \(n = 239\) 是合法的.因为: \(2 \not | 23 ...
- vnpy源码阅读学习(8):关于app
关于app 在入口程序中,我们看到了把 gateway,app, 各类的engine都添加到mainEngine中来.不难猜测gateway主要是处理跟外部的行情,接口各方面的代码,通过别人的文章也不 ...
- 利用 MinIO 轻松搭建静态资源服务
目录 1 引言 2 MinIO 简介 3 MinIO 运行与静态资源使用 3.1 MinIO 获取 3.2 MinIO 启动与运行 3.2.1 前台简单启动 3.2.2 后台指定参数运行 3.2.3 ...
- CentOS7 部署 Hadoop 3.2.1 (伪分布式)
CentOS: Linux localhost.localdomain 3.10.0-862.el7.x86_64 #1 SMP Fri Apr 20 16:44:24 UTC 2018 x86_64 ...
- vue基础指令学习
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- linux pdftk
部分内容来源网络,如有版权问题,请联系删除: http://xuqin.blog.51cto.com/5183168/1117780, http://blog.sina.com.cn/s/blog ...
- OpenCV-Python 轮廓属性 | 二十三
目标 在这里,我们将学习提取一些常用的物体属性,如坚实度,等效直径,掩模图像,平均强度等.更多的功能可以在Matlab regionprops文档中找到. (注:质心.面积.周长等也属于这一类,但我们 ...
- 面试刷题26:新冠攻击人类?什么攻击java平台?
可恶的新冠病毒攻击人类,搞得IT就业形势相当不好?好在有钟南山院士带领我们提前开展好了防护工作! java作为基础平台安装在各种移动设备,PC,小型机,分布式服务器集群,各种不同的操作系统上.所以,对 ...