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

模拟退火算法(Simulated Annealing,SA)最早的思想是由N. Metropolis等人于1953年提出。1983 年,S. Kirkpatrick 等成功地将退火思想引入到组合优化领域。

来源于固体退火原理,将固体加温至充分高,再让其徐徐冷却,加温时,固体内部粒子随温升变为无序状,内能增大,而徐徐冷却时粒子渐趋有序,在每个温度都达到平衡态,最后在常温时达到基态,内能减为最小。

它是基于Monte-Carlo(蒙特卡洛)迭代求解策略的一种随机寻优算法,其出发点是基于物理中固体物质的退火过程与一般组合优化问题之间的相似性。

模拟退火算法从某一较高初温出发,伴随温度参数的不断下降,结合概率突跳特性在解空间中随机寻找目标函数的全局最优解,即在局部最优解能概率性地跳出并最终趋于全局最优。模拟退火算法是一种通用的优化算法,理论上算法具有概率的全局优化性能,目前已在工程中得到了广泛应用,诸如VLSI、生产调度、控制工程、机器学习、神经网络、信号处理等领域。

模拟退火算法是通过赋予搜索过程一种时变且最终趋于零的概率突跳性,从而可有效避免陷入局部极小并最终趋于全局最优的串行结构的优化算法。

这里的“一定的概率”的计算参考了金属冶炼的退火过程,这也是模拟退火算法名称的由来。

根据热力学的原理,在温度为T时,出现能量差为dE的降温的概率为P(dE),表示为:

P(dE) = exp( dE/(kT) )

其中k是一个常数,exp表示自然指数,且dE<0。这条公式说白了就是:温度越高,出现一次能量差为dE的降温的概率就越大;温度越低,则出现降温的概率就越小。又由于dE总是小于0(否则就不叫退火了),因此dE/kT < 0 ,所以P(dE)的函数取值范围是(0,1) 。

随着温度T的降低,P(dE)会逐渐降低。我们将一次向较差解的移动看做一次温度跳变过程,我们以概率P(dE)来接受这样的移动。

二、什么是智能优化算法

启发式算法,是一种具有全局优化性能、通用性强且适用于并行处理的算法。这种算法一般具有严密的理论依据,而不是单纯凭专家经验,理论上可以在一定的时间内找到最优解或近似最优解。

常用的智能优化算法

遗传算法(Genetic Algorithm, GA)

模拟退火算法(Simulated Annealing, SA)

禁忌搜索算法(Tabu Search, TS)

神经网络 (Neural Network)

蚁群算法(Ant Colony Optimization,ACO)

爬山算法(局部最优解法) ( Hill Climbing )

三、TSP问题描述

旅行商问题描述的是一个旅行商要在N之间游走来贩卖货物,而路费的成本与距离成正比,因此他想在N个城市之间找到仅一条最短路径,即能去所有城市一次且仅一次,最后回到出发点。

这个简单的问题被证明为NP问题,对于N个城市的问题计算量为O(N!),对于N=40时的计算量就已是目前全世界最强的计算机都难以解决。因此必须寻找其它的可行的算法(TSP问题算法目前有:爬山、禁忌、蚁群、退火、遗传算法),模拟退火算法就是其中一种。

模拟退火算法其特点是在开始搜索阶段解的质量提高比较缓慢,但是到了迭代后期,它的解的质量提高明显,所以如果在求解过程中,对迭代步数限制比较严格的话,模拟退火算法在有限的迭代步数内很难得到高质量的解。总体而言模拟退火算法比较适合用于有充足计算资源的问题求解。

根据Metropolis准则,粒子在温度T时趋于平衡的概率为exp(-ΔE/(kT)),其中E为温度T时的内能,ΔE为其改变数,k为Boltzmann常数。

若f( Y(i+1) ) <= f( Y(i) ) (即移动后得到更优解),则总是接受该移动;

若f( Y(i+1) ) > f( Y(i) ) (即移动后的解比当前解要差),则以一定的概率接受移动,而且这个概率随着时间推移逐渐降低(逐渐降低才能趋向稳定)相当于上图中,从B移向BC之间的小波峰时,每次右移(即接受一个更糟糕值)的概率在逐渐降低。如果这个坡特别长,那么很有可能最终我们并不会翻过这个坡。如果它不太长,这很有可能会翻过它,这取决于衰减 t 值的设定。

====================

模拟退火算法 伪代码

s:=s0;e:=E(s)//设定目前状态为s0,其能量E(s0)

k:=0//评估次数k

whilekemax//若还有时间(评估次数k还不到kmax)且结果还不够好(能量e不够低)则:

sn:=neighbour(s)//随机选取一临近状态sn

en:=Esn)//sn的能量为E(sn)

ifrandom()

s:=sn;e:=en//移至临近状态sn

k:=k+1//评估完成,次数k加一

returns//回转状态s

===============

模拟退火算法python有库可以调用,实现起来很简单

Python 代码实现编辑

step1:在GitHub上下载常用的 scikit-opt [2] 库。

step2:设立目标函数并执行模拟退火算法。

defdemo_func(x):

x1, x2, x3=xreturn x1 ** 2 + (x2 - 0.05) ** 2 + x3 ** 2

from sko.SA importSA

sa= SA(func=demo_func, x0=[1, 1, 1])

x_star, y_star=sa.fit()

step2(2):如果是最短路径问题(TSP)

sa_tsp= SA_TSP(func=demo_func, x0=range(num_points))

best_points, best_distance= sa_tsp.fit()

====================

TSP问题的SA算法PHP实现

{private $map;//地图,按照矩阵的方式

private $n;//地图规模

private $T;//初始温度T

private $L;//每个温度下达到降温状态的迭代次数

private $l;//降温常数小于却接近于1的常数。λ通常的取值在0.8至0.99之间。在每一温度下,实验足够多的转移次数

private $ord_temp;//降温终止条件,相当于降温到常温

private $path;//输出结果

public function __construct($_map,$_n,$_T,$_L)

{$this->map = $_map;$this->n = $_n;$this->T = $_T;$this->L = $_L;$this->l = 0.95;$this->ord_temp = 1;

}function randomFloat($min = 0, $max = 1)

{return $min + mt_rand() / mt_getrandmax() * ($max - $min);

}public functionoutput()

{foreach($this->path as $key => $value)

{echo $value."->";

}

}//第二个元素向右随机移动1至n-2位

public function new_S($_S)

{$temp_S = $_S;$shift = rand(1,$this->n-2);$ts = $temp_S[1];$temp_S[1] = $temp_S[1+$shift];$temp_S[1+$shift] = $ts;return $temp_S;

}public function cost($_S)

{$_cost = 0;for($i=0;$in-1;$i++)

{$_cost += $this->map[$_S[$i]][$_S[$i+1]];

}$_cost += $this->map[$_S[$i]][0];return $_cost;

}public functioncalculate()

{//初始解

$S = array();for($i=0;$in;$i++)

{$S[$i] = $i;

}$S[] = 0;$this->path = $S;//进入降温过程,初始温度为T

$t = $this->T;while($t > $this->ord_temp)

{for($i=0;$iL;$i++)

{//产生新解

$S1 = $this->new_S($S);//判断新解的价值

$K = $this->cost($S1) - $this->cost($S);if($K < 0)

{$S = $S1;if($this->cost($S) < $this->cost($this->path))$this->path = $S;

}else{//不好的解根据Metropolis准则接受

if($this->randomFloat(0,1) < exp(-$K/$t))

{$S = $S1;

}

}

}//这里可以按照如果连续几次降温能量不变作为终止循序条件

//本例按照降温到常温终止,不计算是否能量不变,需要初始温度给定足够好

$t = $t * $this->l;

}//输出结果

$this->output();echo '
The min cost is '.$this->cost($this->path);

}

}?>

调用过程:

$map = array(array(0,3,6,7),

array(5,0,2,3),

array(6,4,0,2),

array(3,7,5,0),);$n = 4;$T = 20;$L = 100;$SA = new SimulatedAnnealing($map,$n,$T,$L);$SA->calculate();

结果输出:

0->1->2->3->0->

The min cost is 10

=========================

TSP问题JAVA实现代码:

packagenoah;importjava.io.BufferedReader;importjava.io.FileInputStream;importjava.io.IOException;importjava.io.InputStreamReader;importjava.util.Random;public classSA {private int cityNum; //城市数量,编码长度

private int N;//每个温度迭代步长

private int T;//降温次数

private float a;//降温系数

private float t0;//初始温度

private int[][] distance; //距离矩阵

private int bestT;//最佳出现代数

private int[] Ghh;//初始路径编码

private intGhhEvaluation;private int[] bestGh;//最好的路径编码

private intbestEvaluation;private int[] tempGhh;//存放临时编码

private inttempEvaluation;privateRandom random;publicSA() {

}/*** constructor of GA

*

*@paramcn

* 城市数量

*@paramt

* 降温次数

*@paramn

* 每个温度迭代步长

*@paramtt

* 初始温度

*@paramaa

* 降温系数

*

**/

public SA(int cn, int n, int t, float tt, floataa) {

cityNum=cn;

N=n;

T=t;

t0=tt;

a=aa;

}//给编译器一条指令,告诉它对被批注的代码元素内部的某些警告保持静默

@SuppressWarnings("resource")/*** 初始化Tabu算法类

*@paramfilename 数据文件名,该文件存储所有城市节点坐标数据

*@throwsIOException*/

private void init(String filename) throwsIOException {//读取数据

int[] x;int[] y;

String strbuff;

BufferedReader data= new BufferedReader(newInputStreamReader(newFileInputStream(filename)));

distance= new int[cityNum][cityNum];

x= new int[cityNum];

y= new int[cityNum];for (int i = 0; i < cityNum; i++) {//读取一行数据,数据格式1 6734 1453

strbuff =data.readLine();//字符分割

String[] strcol = strbuff.split(" ");

x[i]= Integer.valueOf(strcol[1]);//x坐标

y[i] = Integer.valueOf(strcol[2]);//y坐标

}//计算距离矩阵//,针对具体问题,距离计算方法也不一样,此处用的是att48作为案例,它有48个城市,距离计算方法为伪欧氏距离,最优值为10628

for (int i = 0; i < cityNum - 1; i++) {

distance[i][i]= 0; //对角线为0

for (int j = i + 1; j < cityNum; j++) {double rij =Math

.sqrt(((x[i]- x[j]) * (x[i] - x[j]) + (y[i] -y[j])* (y[i] - y[j])) / 10.0);//四舍五入,取整

int tij = (int) Math.round(rij);if (tij

distance[i][j]= tij + 1;

distance[j][i]=distance[i][j];

}else{

distance[i][j]=tij;

distance[j][i]=distance[i][j];

}

}

}

distance[cityNum- 1][cityNum - 1] = 0;

Ghh= new int[cityNum];

bestGh= new int[cityNum];

bestEvaluation=Integer.MAX_VALUE;

tempGhh= new int[cityNum];

tempEvaluation=Integer.MAX_VALUE;

bestT= 0;

random= newRandom(System.currentTimeMillis());

System.out.println(cityNum+","+N+","+T+","+a+","+t0);

}//初始化编码Ghh

voidinitGroup() {inti, j;

Ghh[0] = random.nextInt(65535) %cityNum;for (i = 1; i < cityNum;)//编码长度

{

Ghh[i]= random.nextInt(65535) %cityNum;for (j = 0; j < i; j++) {if (Ghh[i] ==Ghh[j]) {break;

}

}if (j ==i) {

i++;

}

}

}//复制编码体,复制编码Gha到Ghb

public void copyGh(int[] Gha, int[] Ghb) {for (int i = 0; i < cityNum; i++) {

Ghb[i]=Gha[i];

}

}public int evaluate(int[] chr) {//0123

int len = 0;//编码,起始城市,城市1,城市2...城市n

for (int i = 1; i < cityNum; i++) {

len+= distance[chr[i - 1]][chr[i]];

}//城市n,起始城市

len += distance[chr[cityNum - 1]][chr[0]];returnlen;

}//邻域交换,得到邻居

public void Linju(int[] Gh, int[] tempGh) {inti, temp;intran1, ran2;for (i = 0; i < cityNum; i++) {

tempGh[i]=Gh[i];

}

ran1= random.nextInt(65535) %cityNum;

ran2= random.nextInt(65535) %cityNum;while (ran1 ==ran2) {

ran2= random.nextInt(65535) %cityNum;

}

temp=tempGh[ran1];

tempGh[ran1]=tempGh[ran2];

tempGh[ran2]=temp;

}public voidsolve() {//初始化编码Ghh

initGroup();

copyGh(Ghh, bestGh);//复制当前编码Ghh到最好编码bestGh

bestEvaluation =evaluate(Ghh);

GhhEvaluation=bestEvaluation;int k = 0;//降温次数

int n = 0;//迭代步数

float t =t0;float r = 0.0f;while (k

n= 0;while (n

Linju(Ghh, tempGhh);//得到当前编码Ghh的邻域编码tempGhh

tempEvaluation =evaluate(tempGhh);if (tempEvaluation

{

copyGh(tempGhh, bestGh);

bestT=k;

bestEvaluation=tempEvaluation;

}

r=random.nextFloat();if (tempEvaluation r) {

copyGh(tempGhh, Ghh);

GhhEvaluation=tempEvaluation;

}

n++;

}

t= a *t;

k++;

}

System.out.println("最佳长度出现代数:");

System.out.println(bestT);

System.out.println("最佳长度");

System.out.println(bestEvaluation);

System.out.println("最佳路径:");for (int i = 0; i < cityNum; i++) {

System.out.print(bestGh[i]+ ",");if (i % 10 == 0 && i != 0) {

System.out.println();

}

}

}/***@paramargs

*@throwsIOException*/

public static void main(String[] args) throwsIOException {

System.out.println("Start....");

SA sa= new SA(48, 40, 400, 250.0f, 0.98f);

sa.init("c://data.txt");

sa.solve();

}

}

==================

C++实现的代码:

#include #include#include#include#include#include#include

#define N 30 //城市数量

#define T 3000 //初始温度

#define EPS 1e-8 //终止温度

#define DELTA 0.98 //温度衰减率

#define LIMIT 1000 //概率选择上限

#define OLOOP 20 //外循环次数

#define ILOOP 100 //内循环次数

using namespacestd;//定义路线结构体

structPath

{intcitys[N];doublelen;

};//定义城市点坐标

structPoint

{doublex, y;

};

Path bestPath;//记录最优路径

Point p[N]; //每个城市的坐标

double w[N][N]; //两两城市之间路径长度

int nCase; //测试次数

doubledist(Point A, Point B)

{return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y -B.y));

}void GetDist(Point p[], intn)

{for(int i = 0; i < n; i++)for(int j = i + 1; j < n; j++)

w[i][j]= w[j][i] =dist(p[i], p[j]);

}void Input(Point p[], int &n)

{

scanf("%d", &n);for(int i = 0; i < n; i++)

scanf("%lf %lf", &p[i].x, &p[i].y);

}void Init(intn)

{

nCase= 0;

bestPath.len= 0;for(int i = 0; i < n; i++)

{

bestPath.citys[i]=i;if(i != n - 1)

{

printf("%d--->", i);

bestPath.len+= w[i][i + 1];

}elseprintf("%d", i);

}

printf("Init path length is : %.3lf", bestPath.len);

printf("-----------------------------------");

}void Print(Path t, intn)

{

printf("Path is :");for(int i = 0; i < n; i++)

{if(i != n - 1)

printf("%d-->", t.citys[i]);elseprintf("%d", t.citys[i]);

}

printf("The path length is : %.3lf", t.len);

printf("-----------------------------------");

}

Path GetNext(Path p,intn)

{

Path ans=p;int x = (int)(n * (rand() / (RAND_MAX + 1.0)));int y = (int)(n * (rand() / (RAND_MAX + 1.0)));while(x ==y)

{

x= (int)(n * (rand() / (RAND_MAX + 1.0)));

y= (int)(n * (rand() / (RAND_MAX + 1.0)));

}

swap(ans.citys[x], ans.citys[y]);

ans.len= 0;for(int i = 0; i < n - 1; i++)

ans.len+= w[ans.citys[i]][ans.citys[i + 1]];

cout<< "nCase =" << nCase <

Print(ans, n);

nCase++;returnans;

}void SA(intn)

{double t =T;

srand((unsigned)(time(NULL)));

Path curPath=bestPath;

Path newPath=bestPath;int P_L = 0;int P_F = 0;while(1) //外循环,主要更新参数t,模拟退火过程

{for(int i = 0; i < ILOOP; i++) //内循环,寻找在一定温度下的最优值

{

newPath=GetNext(curPath, n);double dE = newPath.len -curPath.len;if(dE < 0) //如果找到更优值,直接更新

{

curPath=newPath;

P_L= 0;

P_F= 0;

}else{double rd = rand() / (RAND_MAX + 1.0);//如果找到比当前更差的解,以一定概率接受该解,并且这个概率会越来越小

if(exp(dE / t) > rd && exp(dE / t) < 1)

curPath=newPath;

P_L++;

}if(P_L >LIMIT)

{

P_F++;break;

}

}if(curPath.len

bestPath=curPath;if(P_F > OLOOP || t

t*=DELTA;

}

}int main(int argc, const char *argv[]) {

freopen("TSP.data", "r", stdin);intn;

Input(p, n);

GetDist(p, n);

Init(n);

SA(n);

Print(bestPath, n);

printf("Total test times is : %d", nCase);return 0;

}

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

  1. 编程笔试(解析及代码实现):猴子吃桃。猴子第一天吃了若干个桃子,当即吃了一半,还不解馋,又多吃了一个…的C++、Java、Python、C#等语言代码实现

    编程笔试(解析及代码实现):猴子吃桃.猴子第一天吃了若干个桃子,当即吃了一半,还不解馋,又多吃了一个. 第二天早上又将剩下的桃子吃了一半,还是不过瘾,又多吃了一个.以后每天都吃前一天剩下的一半再加一个 ...

  2. 算法_数学问题_Question11_换分币(java实现)

    这篇文章讲述的是算法初级部分的换分币问题的java实现,参考的书籍为清华大学出版社出版,贾蓓等编著的<c语言趣味编程1000例>,如有错误或者不当之处,还望各位大神批评指正. 问题描述 将 ...

  3. 算法_数学问题_Question5_出售金鱼(java实现)

    这篇文章讲述的是算法初级部分的出售金鱼问题的java实现,参考的书籍为清华大学出版社出版,贾蓓等编著的<c语言趣味编程1000例>,如有错误或者不当之处,还望各位大神批评指正. 问题描述 ...

  4. python回溯算法_什么是回溯法,Python解法交流?

    只有去多做题,才能慢慢掌握.力扣​leetcode-cn.com LeetCode 上的解释 回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就 ...

  5. python实现排序算法_数据结构之(3)python实现排序算法

    常用排序与插入算法 冒泡排序 冒泡排序(英语:Bubble Sort)是一种简单的排序算法.它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.遍历数列的工作是重复地进行直 ...

  6. matlab 随机森林算法_(六)如何利用Python从头开始实现随机森林算法

    博客地址:https://blog.csdn.net/CoderPai/article/details/96499505 点击阅读原文,更好的阅读体验 CoderPai 是一个专注于人工智能在量化交易 ...

  7. java byte 判断相等_转发收藏 | 史上最全Java面试题+面试网站推荐!(含答案)

    今天要谈的主题是关于求职,求职是在每个技术人员的生涯中都要经历多次.对于我们大部分人而言,在进入自己心仪的公司之前少不了准备工作,有一份全面细致面试题将帮助我们减少许多麻烦. 相关概念 面向对象的三个 ...

  8. 百度java的线程技术_自我提升(基础技术篇)——java线程简介

    前言:虽然自己平时都在用多线程,也能完成基本的工作需求,但总觉得,还是对线程没有一个系统的概念,所以,查阅了一些资料,理解那些大神和官方的资料,写这么一篇关于线程的文章 本来想废话一番,讲讲自己的经历 ...

  9. 用java编写验证码程序_编写,验证和分析实时Java应用程序

    本文是" 用实时Java开发"系列的第三篇也是最后一部分,展示了如何设计,编写,验证和分析基本的实时应用程序. 我们将说明: 应用程序的时间和性能要求. 为什么传统的非实时Java ...

最新文章

  1. 找对象的过程中,我竟然理解了什么是机器学习!
  2. 如何使用Leangoo管理Sprint Backlog
  3. 新书推荐 |《PostgreSQL实战》出版
  4. node第三方登陆github(express)
  5. spring mvc 自动生成代码
  6. oracle 作业 断开原因,解惑 | Oracle JOB 异常中断原因分析
  7. 全球及中国智能交通行业应用方向分析及创新发展战略报告2021版
  8. JSON 常量详情参考 (内含对中文不转义的参数)
  9. (25)VHDL实现与(数据流描述)
  10. 华为将发布“鸿蒙”以取代 Android 系统
  11. LeetCode Student Attendance Record I
  12. Mysql 使用Maxscale读写分离,负载均衡
  13. 软件测试面试经常会被问到的三大问题(面试常考)
  14. java fadein_原生JS实现 fadeIn / fadeOut 方法
  15. 正式工作后的一些变化和感受
  16. 如何用Python + baidu-aip 实现人脸识别?
  17. rac的FAILOVER 和LOAD_BALANCE参数,yes和on是否通用!
  18. php实现离线挂机,自动离线挂机脚本下线自动挂机脚本
  19. ZOJ1005 Jugs
  20. 写给安徽合肥高三的你——少年不惧岁月长,敢挽桑弓射玉衡

热门文章

  1. USB product id / vendor id 对应厂商查询
  2. 知乎宣布完成2.7亿美元融资 引入前蜜芽合伙人孙伟为CFO
  3. 保罗·艾伦去世:他是微软帝国缔造者,最慷慨的慈善家
  4. spring data jpa 多对多查询
  5. 自动补水排气定压机组工作原理
  6. 从小白开始自学数据结构——第十二天【图及其基本概念和邻接表的定义】
  7. Vue main.js各种写法和含义
  8. ultraos win10启动盘_win10系统使用Ultraiso制作U盘启动盘的设置教程
  9. Java日志管理最佳实践
  10. 2021-2022学年广州市执信中学九年级第一学期期中考试英语试题