这个算法收敛速度还算满意。此算法可以计算n皇后问题,只需要将n改为相应整数即可!
主程序:
clear;
clc;
%%
%八皇后问题,8X8的棋盘上,放置8个皇后,使之两两都不能攻击
%使用退火算法计算
%初始的状态,随机在棋盘上放置8个皇后,每列放一个,使每一行都不能攻击
n = 8; %8皇后
%%
%产生一个随机的状态
state = randperm(n);
%%
%计算当前状态的h函数值(与目标状态的差距,h越大,差距越大。h=0代表此状态即为目标状态)
h = fun_c(state);
disp(state);
disp([‘初始状态的h为‘,num2str(h)]);
%%
%用退火算法从初始状态产生新的状态
%从时间1开始,t代表时间
t = 1;
t_max = 1e5; %允许循环的最大时间
plt = zeros(3,t_max);
while t < t_max && h ~=0
%交换现在状态中的任意两个数
i_rand = 1;
j_rand = 1;
while i_rand == j_rand
i_rand = randi(n);
j_rand = randi(n);
end
state_tmp = state;
tmp = state_tmp(i_rand);
state_tmp(i_rand) = state_tmp(j_rand);
state_tmp(j_rand) = tmp;
h_tmp = fun_c(state_tmp);
if h_tmp <= h
state = state_tmp;
h = h_tmp;
elseif h_tmp > h
T = fun_temp(t); % 当前温度
%温度越高,增加的能量越低,此状态的概率越大
p = exp(-(h_tmp-h)*500/T);
%有一定的概率接受此状态
if p > rand(1)
state = state_tmp;
h = h_tmp;
end
end
plt(1,t) = t;
plt(2,t) = fun_temp(t);
plt(3,t) = h;
t = t + 1;
end
figure(1);
axis auto;
plot(plt(1,1:(t-1)),plt(2,1:(t-1)),‘b‘); %t VS T
hold on;
plot(plt(1,1:(t-1)),100*plt(3,1:(t-1)),‘r‘); %t VS h
hold off;
%%
if h == 0
disp(‘退火算法成功‘);
else
disp(‘退火算法失败‘);
end
disp([‘经历的时间为‘,num2str(t)]);
disp([‘最终状态的h为‘,num2str(h)]);
disp(state);
%将state转换成nXn矩阵
state_full = zeros(n,n);
for i=1:n
for j=1:n
if j == state(i)
state_full(i,j) = 1;
end
end
end
%%
%显示最终的状态
disp(state_full);
各子函数
function [h] = fun_c(state)
%根据一个状态,评价它的代价函数
h = 0;
n = length(state);
%%
%每列的状态,看有多少个能互相攻击,每两两攻击算一次
for i=1:n
count = length(find(state == i));
if count > 1;
h = h + nchoosek(count,2);
end
end
%%
%将state转换成nXn矩阵
state_full = zeros(n,n);
for i=1:n
for j=1:n
if j == state(i)
state_full(i,j) = 1;
end
end
end
%%
%每个左斜对角的状态,看有多少个能互相攻击,每两两攻击算一次
i=1;
j=1;
add = 0;
while i<n+1 && j<n+1 && i>0 && j>0
%计算左斜对角每条线有多少个皇后
count = fun_calc_left(i,j,n,state_full);
if count > 1;
h = h + nchoosek(count,2);
end
if add == 0;
j = j + 1;
elseif add == 1;
i = i + 1;
end
add = ~add;
end
%%
%每个右斜对角的状态,看有多少个能互相攻击,每两两攻击算一次
i=1;
j=n;
add = 0;
while i<n+1 && j<n+1 && i>0 && j>0
%计算右斜对角有多少个皇后
count = fun_calc_right(i,j,n,state_full);
if count > 1;
h = h + nchoosek(count,2);
end
if add == 0;
j = j - 1;
elseif add == 1;
i = i + 1;
end
add = ~add;
end
end
function count = fun_calc_left(i,j,n,state_full)
%%
%统计i,j 点,左下角
count = 0;
i_l = i;
i_r = i;
j_l = j;
j_r = j;
while i_l>0 && j_l>0 && i_l<n+1 && j_l<n+1
count = count + state_full(i_l,j_l);
i_l = i_l + 1;
j_l = j_l - 1;
end
%%
%右上角的个数
while i_r>0 && j_r>0 && i_r<n+1 && j_r<n+1
count = count + state_full(i_r,j_r);
i_r = i_r - 1;
j_r = j_r + 1;
end
%%
%被重复加的,减去
count = count - state_full(i,j);
end
function count = fun_calc_right(i,j,n,state_full)
%%
%统计i,j 点,左上角
count = 0;
i_l = i;
i_r = i;
j_l = j;
j_r = j;
while i_l>0 && j_l>0 && i_l<n+1 && j_l<n+1
count = count + state_full(i_l,j_l);
i_l = i_l - 1;
j_l = j_l - 1;
end
%%
%右下角的个数
while i_r>0 && j_r>0 && i_r<n+1 && j_r<n+1
count = count + state_full(i_r,j_r);
i_r = i_r + 1;
j_r = j_r + 1;
end
%%
%被重复加的,减去
count = count - state_full(i,j);
end
function T = fun_temp(t)
%给定退火的时间和速率,t为时间,T为温度
if t<= 50
T = 1000;
elseif t>50 && t<1000
T = 1000 - ( t - 50 )*100/95;
else
T = 1e-3;
end
end
原文:http://www.cnblogs.com/shekarry/p/5361362.html