智能算法之模拟退火算法
模拟退火算法来源于热力学中固体物质的退火冷却过程 (退火是一种金属热处理工艺,指的是将金属缓慢加热到一定温度,保持足够时间,然后以适宜速度冷却)。
模拟退火的算法思想是参考物理退火的过程而来,物理退火的过程为:加温过程 -> 等温过程 -> 冷却过程。
通过加温,增强粒子的热运动,让各部分变得均匀。当温度足够高时,固体将熔解为液体,从而消除原先系统中可能存在的非均匀状态,保证后续进行的过程是从平衡态开始,由于是加温过程温度上升,所以该过程系统能量增加。
对于与周围环境交换热量而温度保持不变的封闭系统,系统状态的自发变化总是朝着自由能减少的方向进行,当自由能达到最小时,系统达到平衡态。
通过一定速率对液体进行冷却,减弱粒子的热运动并趋于有序,在每个温度都达到平衡态,最后在常温时达到基态,能量减为最小,从而得到低能态的晶体结构。
| 组合优化 | 物理退火 |
|---|---|
| 解 | 粒子状态 |
| 最优解 | 能量最低态 |
| 设定初温 | 熔解过程 |
| M e t r o p o l i s Metropolis Metropolis 抽样过程 | 等温过程 |
| 控制参数下降 | 冷却过程 |
| 目标函数 | 能量 |
模拟退火算法的基本原理:对于目标函数 f ( X ) f(X) f(X)、自变量为 X X X 的 n n n 维极小化问题(极大化问题乘以 − 1 -1 −1转化为极小化问题),初值 X 0 X_0 X0 可以随机化或者自己设置。
设
f
k
,
f
k
+
1
f_k,f_{k+1}
fk,fk+1 分别为目标函数在第
k
k
k 次和第
k
+
1
k+1
k+1 次迭代值,即
f
k
=
f
(
X
k
)
,
f
k
+
1
=
f
(
X
k
+
1
)
f_k=f(X_k),f_{k+1}=f(X_{k+1})
fk=f(Xk),fk+1=f(Xk+1)。
若
f
k
>
f
k
+
1
f_k>f_{k+1}
fk>fk+1,则接受
X
k
+
1
X_{k+1}
Xk+1 作为下一次迭代的初值继续进行运算,直至满足终止条件(收敛或者迭代次数耗尽);
若
f
k
<
f
k
+
1
f_k<f_{k+1}
fk<fk+1,则接受
X
k
+
1
X_{k+1}
Xk+1 的概率为
p
p
p,拒绝的概率为
1
−
p
1-p
1−p,其中接受概率公式如下:
p
=
e
x
p
(
−
f
k
+
1
−
f
k
T
)
p=exp(-\frac{f_{k+1}-f_k}{T})
p=exp(−Tfk+1−fk) 其中
T
T
T 为控制参数,在模拟退火算法中,
T
T
T 必须缓慢减少,避免变化过快,导致优化陷入极值点。
以求解极小值问题为例:
(
1
)
(1)
(1)设定初始温度
T
T
T,迭代次数
L
L
L,误差
ϵ
\epsilon
ϵ,初始解
X
0
X_0
X0,得到目标函数
f
(
X
0
)
f(X_0)
f(X0);
(
2
)
(2)
(2)循环进行迭代,
k
=
1
,
⋯
,
L
k=1,\cdots,L
k=1,⋯,L;
(
3
)
(3)
(3)根据当前温度得到新解
X
′
X'
X′(第一个可以随机生成), 代入
f
(
X
)
f(X)
f(X) 得到
f
(
X
′
)
f(X')
f(X′);
(
4
)
(4)
(4)若
f
(
X
)
>
f
(
X
′
)
f(X)>f(X')
f(X)>f(X′),则接受
X
′
X'
X′ 作为下一次迭代的初值,若
f
(
X
)
<
f
(
X
′
)
f(X)<f(X')
f(X)<f(X′),则以概率
e
x
p
(
−
f
(
X
′
)
−
f
(
X
)
T
)
exp(-\frac{f(X')-f(X)}{T})
exp(−Tf(X′)−f(X)) 接受
X
′
X'
X′ 作为下一次迭代的初值;
(
5
)
(5)
(5)若满足终止条件,则输出当前最优解
X
′
X'
X′,终止条件;
(
6
)
(6)
(6)
T
T
T 减小,然后回到流程
(
2
)
(2)
(2),在当前温度下继续循环迭代,执行步骤
(
3
,
4
,
5
)
(3,4,5)
(3,4,5);
(
7
)
(7)
(7)注意,这里的终止条件可以有多个,比如:迭代次数耗尽、满足最优解、温度降低到一定值、新目标函数与原先目标函数的误差小于
ϵ
\epsilon
ϵ。
例1:求解函数
f
(
X
)
=
X
2
f(X)=X^2
f(X)=X2 的最小值,其中
X
2
=
∑
i
=
1
10
x
2
X^2=\sum_{i=1}^{10}x^2
X2=∑i=110x2,
−
10
≤
x
≤
10
-10\leq x\leq 10
−10≤x≤10。
下面通过matlab进行求解:
目标函数:
%--------目标函数f(x)---------
function result = func1(x)
result = sum(x.^2);
end
模拟退火算法:
clear; clc;
%---------------------模拟退火核心-------------------------------
L = 200; % 每个温度的迭代次数
epsilon = 1e-10; % 新目标函数与原先目标函数的误差
T0 = 200; % 初始温度
T1 = 0.00001; % 终止温度
s = 0.01; % 自变量更新的步长,相当于学习率
K = 0.998; % 温度衰减参数
P = 0; % Metropolis 过程中总接受点
%---------------------根据题目所写--------------------------------
opt_minmax = 1; % 求解极小值问题为1,极大值问题为-1
n = 10; % 自变量维度
up = 10; % 自变量上限
sup = -10; % 自变量下限
x0 = rand(n, 1)*(up-sup)-up; % 随机生成在范围内的初始自变量
x1 = rand(n, 1)*(up-sup)-up; % 随机生成在范围内的 x1 自变量进行第一步
PreBest = x0;
NowBest = x1;
%---------------------进行迭代----------------------------------
delta = abs(func1(NowBest) - func1(PreBest));
while (delta > epsilon) && (T0 > T1)
T0 = K*T0;
for i = 1:L
x2 = x1 + s*(rand(n, 1)*(up-sup)-up);
%-----下面这个循环是写题目的条件的,这里没啥好些,就重复了边界条件
for j = 1:n
while (x2(j) > up) || (x2(j) < sup)
x2(j) = x1(j) + s*(rand*(up-sup)-up);
end
end
%--------------查看解是否是全局最优解----------------
if opt_minmax*func1(NowBest) > opt_minmax*func1(x2)
PreBest = NowBest; % 保留上一个最优解
NowBest = x2; % 保留新的最优解
end
%---------------- Metropolis过程--------------------
if opt_minmax*func1(x1) > opt_minmax*func1(x2)
x1 = x2;
P = P + 1;
else
p = exp(-(func1(x2)-func1(x1))/T0);
if p > rand(1)
x1 = x2;
P = P + 1;
end
end
Y(P) = func1(NowBest);
end
delta = abs(func1(NowBest) - func1(PreBest));
end
得到结果为:
X
=
[
−
0.0114
,
−
0.0002
,
0.0020
,
0.0101
,
0.0074
,
−
0.0003
,
−
0.0084
,
0.0112
,
−
0.0252
,
0.0052
]
X=[-0.0114,-0.0002,0.0020,0.0101,0.0074,-0.0003,-0.0084,0.0112,-0.0252,0.0052]
X=[−0.0114,−0.0002,0.0020,0.0101,0.0074,−0.0003,−0.0084,0.0112,−0.0252,0.0052]
f
(
X
)
=
0.0011
f(X)=0.0011
f(X)=0.0011
绘制适应度进化曲线:
%----------------------------画图--------------------------------
plot(Y, 'r');
hold on
scatter(length(Y), Y(end), 'bo', 'MarkerFaceColor', 'b')
text(length(Y), Y(end), ' 最优点')
xlabel('迭代次数'); ylabel('目标函数值'); title('适应度进化曲线');

例2:求解函数
f
(
x
,
y
)
=
5
c
o
s
(
x
y
)
+
x
y
+
y
3
f(x,y) = 5cos(xy)+xy+y^3
f(x,y)=5cos(xy)+xy+y3 的最小值,其中
−
5
≤
x
≤
5
,
−
5
≤
y
≤
5
-5\leq x\leq 5,-5\leq y\leq 5
−5≤x≤5,−5≤y≤5。
下面通过matlab进行求解:
目标函数:
%--------目标函数f(x)---------------
function result = func1(x)
result = 5*cos(x(1).*x(2))+x(1).*x(2)+x(2).^3;
end
可以看看 f ( x , y ) f(x,y) f(x,y) 的图像:
clear;clc;
x = linspace(-5, 5);
y = linspace(-5, 5);
[x, y] = meshgrid(x, y);
f = 5*cos(x.*y)+x.*y+y.^3;
mesh(x, y, f);
xlabel('x'); ylabel('y'); zlabel('f');

第二种方法适合小白,不过和meshgrid画出来的图相比较发现是翻转过的,所以可以自行选择。
x1 = linspace(-5, 5);
y1 = linspace(-5, 5);
N = size(x1, 2);
for i = 1:N
for j = 1:N
z(i, j)=5*cos(x1(i)*y1(j))+x1(i)*y1(j)+y1(j)^3;
end
end
mesh(x1, y1, z);
xlabel('x1'); ylabel('y1'); zlabel('z');

这次使用matlab自带的模拟退火函数进行求解:
clear; clc;
%---------------------根据题目所写---------------------------------------
options = optimoptions('simulannealbnd','PlotFcns',...
{@saplotbestx,@saplotbestf,@saplotx,@saplotf});
up = [5, 5]; % 自变量x,y上限
sup = [-5, -5]; % 自变量x,y下限
x0 = rand(1, 2).*(up-sup)-up; % 随机生成在范围内的初始自变量x0,y0
func = @(x)(5*cos(x(1)*x(2))+x(1)*x(2)+x(2)^3);
[x, fval] = simulannealbnd(func, x0, sup, up, options)
得到结果为:
f
(
x
,
y
)
=
f
(
4.4242
,
−
5.0000
)
=
−
152.0788
f(x,y)=f(4.4242,-5.0000)=-152.0788
f(x,y)=f(4.4242,−5.0000)=−152.0788

例3:根据下面的所给的条件,给此地的生鲜配送路线进行规划,让生鲜被高效率送到各销售市场中,使得资源达到最大的利用。
n
n
n :销售市场数量;
q
i
q_i
qi:每个市场需求量
(
i
=
1
,
2
,
⋯
,
n
)
(i=1,2,\cdots,n)
(i=1,2,⋯,n);
m
m
m:配送车数量(每辆车都型号都一致);
Q
Q
Q:配送车最大装载量;
d
i
j
d_{ij}
dij:市场
i
i
i 到市场
j
j
j 的距离;
t
i
j
t_{ij}
tij:从市场
i
i
i 到市场
j
j
j 所需时间;
d
o
i
d_{oi}
doi:配送中心
o
o
o 到市场
i
i
i 的距离;
c
0
c_0
c0 :每次配送固定成本;
c
v
c_v
cv:单位里程行驶费用;
v
v
v:配送车匀速行驶速度;
T
T
T:生鲜装卸时间;
β
1
\beta_1
β1:单位时间配送运输损耗比例;
β
2
\beta_2
β2:单位时间配送装卸损耗比例;
u
i
j
k
u_{ijk}
uijk:配送车辆
k
k
k 在
i
i
i 到
j
j
j 路径上行驶时的载重量;
p
p
p:单位重量货物的货损价格;
f
0
f_0
f0:单次配送任务中,配送中心派出的送货车辆总数;
f
v
f_v
fv:单次配送任务中,所有配送车辆行驶里程数之和;
f
b
f_b
fb:单次配送任务中,所有配送线路上产生的货损量之和。
决策变量:
X
i
j
k
=
{
1
,
配送车
k
从市场
(
或配送中心
)
i
到市场
j
0
,
其他
X_{ijk}=\left\{ \begin{aligned} 1, \quad 配送车 k 从市场(或配送中心) i 到市场 j \\ 0, \quad \quad \quad \quad \quad \quad \quad \quad其他 \quad \quad \quad\quad \quad \quad \quad \end{aligned} \right.
Xijk={1,配送车k从市场(或配送中心)i到市场j0,其他
Y
i
k
=
{
1
,
市场
i
的货物由配送车
k
配送
0
,
其他
Y_{ik}=\left\{ \begin{aligned} 1, \quad 市场 i 的货物由配送车k配送 \\ 0, \quad \quad \quad \quad \quad其他\quad \quad \quad \quad\quad \quad \end{aligned} \right.
Yik={1,市场i的货物由配送车k配送0,其他 目标函数
m
i
n
Z
=
m
i
n
(
f
0
c
0
+
f
v
c
v
+
f
b
p
)
min Z = min(f_0c_0+f_vc_v+f_bp)
minZ=min(f0c0+fvcv+fbp)
m
i
n
Z
=
m
i
n
[
k
c
0
+
∑
i
=
0
n
∑
j
=
0
n
∑
k
=
1
m
d
i
j
X
i
j
k
c
v
+
(
∑
i
=
0
n
∑
j
=
0
n
∑
k
=
1
m
β
1
t
i
j
u
i
j
k
X
i
j
k
+
∑
i
=
1
n
∑
k
=
1
m
β
2
T
q
i
Y
i
k
)
p
]
minZ=min[kc_0+\sum_{i=0}^n\sum_{j=0}^n\sum_{k=1}^md_{ij}X_{ijk}c_v \\ + (\sum_{i=0}^n\sum_{j=0}^n\sum_{k=1}^m\beta_1t_{ij}u_{ijk}X_{ijk}+\sum_{i=1}^n\sum_{k=1}^m\beta_2Tq_{i}Y_{ik})p]
minZ=min[kc0+i=0∑nj=0∑nk=1∑mdijXijkcv+(i=0∑nj=0∑nk=1∑mβ1tijuijkXijk+i=1∑nk=1∑mβ2TqiYik)p] 约束条件
每条路线的生鲜需求量之和不超过配送车最大装载量
Q
Q
Q:
∑
i
=
1
n
q
i
Y
i
k
≤
Q
(
k
=
1
,
2
,
⋯
,
m
)
\sum_{i=1}^nq_{i}Y_{ik} \leq Q \quad(k=1,2,\cdots,m)
i=1∑nqiYik≤Q(k=1,2,⋯,m) 每辆车不可能同时去两个市场:
∑
i
=
1
n
X
o
i
k
=
∑
i
=
1
n
X
i
o
k
≤
1
(
k
=
1
,
2
,
⋯
,
m
)
\sum_{i=1}^nX_{oik}=\sum_{i=1}^nX_{iok}\leq1 \quad(k=1,2,\cdots,m)
i=1∑nXoik=i=1∑nXiok≤1(k=1,2,⋯,m) 每个市场只有一辆配送车送货:
∑
k
=
1
m
Y
i
k
=
1
(
i
=
1
,
2
,
⋯
,
n
)
\sum_{k=1}^mY_{ik}=1\quad (i=1,2,\cdots,n)
k=1∑mYik=1(i=1,2,⋯,n) 假设各市场坐标及需求量如下表
| 序号 | x x x | y y y | q q q |
|---|---|---|---|
| 1 | 83 | 263 | 137 |
| 2 | 90 | 302 | 155 |
| 3 | 67 | 300 | 245 |
| 4 | 126 | 273 | 126 |
| 5 | 105 | 102 | 127 |
| 6 | 75 | 246 | 158 |
| 7 | 87 | 320 | 109 |
| 8 | 129 | 72 | 242 |
| 9 | 71 | 332 | 123 |
| 10 | 77 | 153 | 206 |
| 11 | 97 | 136 | 173 |
| 12 | 85 | 286 | 136 |
| 13 | 113 | 173 | 111 |
| 14 | 101 | 301 | 230 |
| 15 | 100 | 324 | 222 |
配送中心坐标为 ( 93 , 245 ) (93,245) (93,245),配送车共7辆,单位里程费用 1 元 / k m 1元/km 1元/km,每次配送固定成本为 100 元 / 辆 100元/辆 100元/辆,平均行驶速度为 50 k m / h 50km/h 50km/h,最大载重量为 500 k g 500kg 500kg,单位配送运输损耗比例为 1 % 1\% 1%,单位装卸损耗比例为 0.5 % 0.5\% 0.5%,生鲜装卸时间为 15 m i n 15min 15min,单位重量货物的货损价格为 10 元 / k g 10元/kg 10元/kg;
编写程序,进行计算
这里用 4.3 的例子坐标进行展示,先编写所需要的
m
a
t
l
a
b
matlab
matlab 函数:
① 让解在迭代中变化,相当于通过
x
1
x_1
x1 随机游走生成
x
2
x_2
x2
% tsp_sa 随机扰动子函数
% 也就是原先的改变步长,这里通过交换两个地点的位置来进行计算
function circle = perturbation(circle)
r = 1 + randperm(length(circle)-2);
tmp = circle(r(1));
circle(r(1)) = circle(r(2));
circle(r(2)) = tmp;
end
② 计算路径总长度,函数输入值为距离矩阵 d d d 和路径 c i r c l e circle circle
% tsp_sa 路线总长度子函数
function len = pathlength(d, circle)
j = length(circle);
len = 0;
for i = 1:j-1
len = len+d(circle(i), circle(i+1));
end
end
③ 模拟退火主函数
% tsp_sa 模拟退火解决 TSP 问题
function [mincircle, minlen] = tsp_sa(d, cool, rho, iter)
% d 是距离矩阵
% rho 是衰减系数
n = size(d, 1); % 地点数量
temperature = 100 * n; % 初始温度
circle = [1:n, 1]; % 初始值
mincircle = circle; % mincircle 是最小路径
minlen = inf; % minlen 是路径的长度
s = 0;
while temperature > cool % cool 是冷却温度
for i= 1:iter % iter 是内循环次数
len1 = pathlength(d, circle); % 计算原路线总长度
newcircle = perturbation(circle); % 产生随机扰动
len2 = pathlength(d, newcircle); % 计算新路线总长度
%---------------------------Metropolis------------------------------
delta = len2 - len1;
if exp(-delta/temperature) > rand
circle = newcircle;
len1 = len2;
end
if len1 < minlen
mincircle = circle;
minlen = len1;
end
end
s = s + 1;
temperature = temperature*rho;
end
end
利用上述函数进行计算,得到结果如下:
clear;clc;
% ----------基础数据---------
market = [
1 83 263 137;
2 90 302 155;
3 67 300 245;
4 126 273 126;
5 105 102 127;
6 75 246 158;
7 87 320 109;
8 129 72 242;
9 71 332 123;
10 77 153 206;
11 97 136 173;
12 85 286 136;
13 113 173 111;
14 101 301 230;
15 100 324 222];
center = [93 245];
A = market(:, 2:3);
B = [center; A];
C = num2str([0 1:size(A, 1)]');
h = pdist(B);
d = squareform(h); % 距离矩阵
% --------------模拟退火初始控制变量---------------
cool = 0.1;
rho = 0.99;
iter = 1000;
% ----------------------求解---------------------
[mincircle, minlen] = tsp_sa(d, cool, rho, iter);
% ----------------------画图---------------------
scatter(B(:,1), B(:, 2), 'ro');
hold on;
plot(B(mincircle, 1), B(mincircle,2), 'g');
hold on;
text(B(:,1), B(:, 2), C);
title(['回路总长度', num2str(minlen)])

现有一大型零售企业的物流中心位于坐标 ( 12 , 12 ) (12,12) (12,12)(单位: k m km km),要给 10 10 10 个超市送货,每个超市的需求量和坐标如下表所示。物流中心共 6 6 6 辆车,每辆车载质量为 40 t 40t 40t,要给这些超市送货,送货后回到起点。每辆车出行基本费用为 200 200 200 元,单位运输成本为 50 元 / k m 50元/km 50元/km,按直线距离计算路程。求配送费用最低的配送方案,用模拟退火算法求解。
| 超市编号 | 需求量 | X | Y |
|---|---|---|---|
| 1 | 10 | 3 | 13 |
| 2 | 15 | 12 | 7 |
| 3 | 21 | 2 | 26 |
| 4 | 9 | 24 | 12 |
| 5 | 25 | 31 | 22 |
| 6 | 18 | 5 | 14 |
| 7 | 23 | 17 | 11 |
| 8 | 15 | 16 | 13 |
| 9 | 8 | 12 | 8 |
| 10 | 13 | 8 | 2 |
(1)主函数
clc;clear;
%% 基础数据
center = [12, 12]; % 物流中心
market = [1, 10, 3, 13; % 超市的需求量和位置
2, 15, 12, 7;
3, 21, 2, 26;
4, 9, 24, 12;
5, 25, 31, 22;
6, 18, 5, 14;
7, 23 17, 11;
8, 15, 16, 13;
9, 8, 12, 8;
10, 13, 8, 2;];
demands = market(:,2); % 超市需求量
cumsum = size(market, 1); % 超市个数
market_xy = market(:, 3:4); % 超市坐标
car = 6; % 最大车辆数
heavy = 40; % 每辆车的最大载重量
cost_0 = 200; % 每辆车出行基本费用
cost_v = 50; % 单位运输成本
punish = 3000; % 单辆车违反约束条件的惩罚
A = [center; market_xy];
h = pdist(A);
d = squareform(h); % 距离矩阵
% --------------模拟退火初始控制变量---------------
cool = 0.1;
rho = 0.99;
iter = 200;
% -----------------------------------------------------------
temperature = 100 * size(d, 1); % 初始温度
init_vc = init(cumsum, demands, heavy); % 路径初始化
[distance_all, n] = path_dist(init_vc, d); % 计算路径总距离和用车数量
mincircle = init_vc;
minlen = inf; % minlen 是路径的长度
% 初始化成功
vc = init_vc;
s = 0;
Y = [];
while temperature > cool % cool 是冷却温度
for i= 1:iter % iter 是内循环次数
% 计算每个路径的距离以及路径的总距离
[distance_all, n] = path_dist(init_vc, d); % 计算路径总距离和用车数量
k = judge(vc, demands, heavy); % 判断是否有违约路径
all_cost1 = cost_0 * n + cost_v * distance_all + k * punish; % 计算成本
path = get_path(vc, cumsum, car); % 将元胞拼接成路径
% 获得新解 path2
path2 = new_path(path);
new_vc = cut_path(path2, cumsum, car); % 将路径切割为元胞
[distance_all2, n] = path_dist(new_vc, d); % 计算路径总距离和用车数量
k2 = judge(new_vc, demands, heavy);
all_cost2 = cost_0 * n + cost_v * distance_all2 + k2 * punish; % 计算成本
%% ---------------------------Metropolis-------------------------------
delta = all_cost2 - all_cost1;
if exp(-delta/temperature) > rand
vc = new_vc;
all_cost1 = all_cost2;
end
if all_cost1 < minlen
mincircle = vc;
minlen = all_cost1;
end
end
s = s + 1;
Y(s) = minlen;
temperature = temperature*rho;
end
minlen
mincircle
plot(Y, 'r')
ylabel('费用'); xlabel('迭代次数');
(2)路径初始化
% 初始化种群
function [init_vc] = init(cusnum, demands, heavy)
j = ceil(rand*cusnum);
k = 1;
init_vc = cell(k, 1);
if j == 1
seq = 1:cusnum;
elseif j == cusnum
seq = [cusnum, 1:j-1];
else
seq1 = 1:j-1;
seq2 = j:cusnum;
seq = [seq2, seq1];
end
route = [];
load = 0;
i = 1;
while i <= cusnum
if load + demands(seq(i)) <= heavy % 满足约束条件则加入路线,不满足则新开一条路线
load = load + demands(seq(i));
if isempty(route)
route = [seq(i)];
else
route = [route, seq(i)];
end
if i == cusnum
init_vc{k, 1} = route;
break
end
i = i + 1;
else
init_vc{k, 1} = route;
route = [];
load = 0;
k = k + 1;
end
end
end
(3)路径长度计算
% 计算路径的总长度
function [distance_all, n] = path_dist(vc, d)
distance_all = zeros(1, length(vc));
n = length(vc);
for i = 1:n
lr = vc{i, 1};
dist = 0;
for j = 1:length(lr)-1
dist = dist + d(lr(j)+1, lr(j+1)+1);
end
dist = dist + d(1, lr(1)+1) + d(lr(end)+1, 1);
distance_all(i) = dist;
end
distance_all = sum(distance_all);
end
(4)约束条件判断
% 判断是否违反约束条件
function k = judge(vc, demands, heavy)
k = 0;
for i = 1:length(vc)
route = vc{i, 1};
if sum(demands(route)) > heavy
k = k + 1;
end
end
end
(5)获得新路径
%% 生成新路径
function path2 = new_path(path)
n = length(path);
path1 = path;
c = randi(n, 1, 2); % 生成1~n中的两个随机整数用于交换
p = 0.6;
if rand < p % 交换法产生新路径,若随机概率落在目标概率内,则交换路径中的两个元素位置
path2 = path1;
path2(c(1)) = path1(c(2));
path2(c(2)) = path1(c(1));
else
path2 = fliplr(path1); % 左右翻转
end
(6)切割一整条路径为多个子路径
% 路径切割
function vc = cut_path(path, cumsum, car)
vc = cell(car, 1);
n = find(path > cumsum);
for i = 1:length(n)
if i == 1
vc{i,1} = path(1:n(i));
vc{i,1}(end) = [];
else
vc{i,1} = path(n(i-1):n(i));
vc{i,1}(1) = [];
vc{i,1}(end) = [];
end
end
vc{end, 1} = path(n(end):end);
vc{end, 1}(1) = [];
vc(cellfun(@isempty, vc)) = [];
end
(7)将多个子路径拼接为一整个路径
% 路线拼接
function path = get_path(vc, cumsum, car)
n = cumsum + car - 1;
path = [];
for i = 1:length(vc)
rount = vc{i, 1};
if i == length(vc)
path = [path rount];
else
path = [path rount cumsum + i];
end
end
if length(path) ~= n
path(length(path)+1:n) = (length(path)+1):n;
end
end
结果得到:5辆车,-> 7 -> 8 -> ,-> 3 ->,-> 1 -> 6 ->,-> 5 -> 4 ->,-> 9 -> 2 -> 10 ->,花费为
7614.5
7614.5
7614.5 元。


1、只需要单个初值就能进行计算,不像群体智能优化算法需要进行初始化种群;
2、可以找到全局最优点,类似梯度下降,但是梯度下降可能会被困在局部解,但是模拟退火有概率突跳性,虽然在温度较高时,接受差解的概率大,但当温度下降时,接受差解的概率就越来越小。
1、收敛速度慢,因为初始温度一般设定得很高,终止温度设定得低,这样才能体现模拟退火的特点,而且接受差解,并不是全程收敛,此时就需要时间跳出来;
2、受到温度、退火速度等模拟退火参数影响较大,比如衰减速度(退火速度)太大,可能会导致找不到全局最优解。
1、可以和其他智能算法结合在一起,比如模拟退火算法负责前半部分,遗传算法负责后半部分;又或者多种算法融合/混合在一起;
2、可以尝试多次找到比较好的模拟退火参数来作为最后使用的值。
[1] 周佳莉. 模拟退火算法的应用[J]. 西部皮革,2019,41(20):82.
[2] 包子阳,余继周,杨杉. 智能优化算法及其MATLAB实例(第3版)
[3] 康雯轩. 基于模拟退火算法的共享单车城市配送路径规划[J]. 科技与创新,2022(13):104-106,109. DOI:10.15913/j.cnki.kjycx.2022.13.032.
[4] 胡良剑,孙晓君. MATLAB数学实验(第3版)
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
matlab打开matlab,用最简单的imread方法读取一个图像clcclearimg_h=imread('hua.jpg');返回一个数组(矩阵),往往是a*b*cunit8类型解释一下这个三维数组的意思,行数、数和层数,unit8:指数据类型,无符号八位整形,可理解为0~2^8的数三个层数分别代表RGB三个通道图像rgb最常用的是24-位实现方法,即RGB每个通道有256色阶(2^8)。基于这样的24-位RGB模型的色彩空间可以表现256×256×256≈1670万色当imshow传入了一个二维数组,它将以灰度方式绘制;可以把图像拆分为rgb三层,可以以灰度的方式观察它figure(1
目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO
假设我在Store的模型中有这个非常简单的方法:defgeocode_addressloc=Store.geocode(address)self.lat=loc.latself.lng=loc.lngend如果我想编写一些不受地理编码服务影响的测试脚本,这些脚本可能已关闭、有限制或取决于我的互联网连接,我该如何模拟地理编码服务?如果我可以将地理编码对象传递到该方法中,那将很容易,但我不知道在这种情况下该怎么做。谢谢!特里斯坦 最佳答案 使用内置模拟和stub的rspecs,你可以做这样的事情:setupdo@subject=MyCl
在ruby中,你可以这样做:classThingpublicdeff1puts"f1"endprivatedeff2puts"f2"endpublicdeff3puts"f3"endprivatedeff4puts"f4"endend现在f1和f3是公共(public)的,f2和f4是私有(private)的。内部发生了什么,允许您调用一个类方法,然后更改方法定义?我怎样才能实现相同的功能(表面上是创建我自己的java之类的注释)例如...classThingfundeff1puts"hey"endnotfundeff2puts"hey"endendfun和notfun将更改以下函数定
我有一个gem,它有一个根据Rails.env的不同行为的方法:defself.envifdefined?(Rails)Rails.envelsif...现在我想编写一个规范来测试这个代码路径。目前我是这样做的:Kernel.const_set(:Rails,nil)Rails.should_receive(:env).and_return('production')...没关系,只是感觉很丑。另一种方法是在spec_helper中声明:moduleRails;end而且效果也很好。但也许有更好的方法?理想情况下,这应该有效:rails=double('Rails')rails.sho
我有一个rspec模拟对象,一个值赋给了属性。我正在努力在我的rspec测试中满足这种期望。只是想知道语法是什么?代码:defcreate@new_campaign=AdCampaign.new(params[:new_campaign])@new_campaign.creationDate="#{Time.now.year}/#{Time.now.mon}/#{Time.now.day}"if@new_campaign.saveflash[:status]="Success"elseflash[:status]="Failed"endend测试it"shouldabletocreat
我正在尝试测试命令行工具的输出。如何使用rspec来“伪造”命令行调用?执行以下操作不起作用:it"shouldcallthecommandlineandreturn'text'"do@p=Pig.new@p.should_receive(:run).with('my_command_line_tool_call').and_return('resulttext')end如何创建stub? 最佳答案 使用newmessageexpectationsyntax:规范/虚拟规范.rbrequire"dummy"describeDummy
1.问题描述使用Python的turtle(海龟绘图)模块提供的函数绘制直线。2.问题分析一幅复杂的图形通常都可以由点、直线、三角形、矩形、平行四边形、圆、椭圆和圆弧等基本图形组成。其中的三角形、矩形、平行四边形又可以由直线组成,而直线又是由两个点确定的。我们使用Python的turtle模块所提供的函数来绘制直线。在使用之前我们先介绍一下turtle模块的相关知识点。turtle模块提供面向对象和面向过程两种形式的海龟绘图基本组件。面向对象的接口类如下:1)TurtleScreen类:定义图形窗口作为绘图海龟的运动场。它的构造器需要一个tkinter.Canvas或ScrolledCanva