我需要在MATLAB中解决n皇后问题,我已经尝试了下面所附的代码。我遇到的问题是,在模拟的某个点上,种群的“检查”卡在了某个值上(接近零但不是我需要的零)。90%的情况都是这样,剩下的10%给出了一个非常快的解决方案(在非常少的迭代中)。也许有些部分没有很好地优化,但这是我最好的尝试。随时询问关于它的任何事情,抱歉,如果评论是西班牙语的,谢谢。
这是我使用的代码,如果你多次运行它,其中只有几个会给予你一个解决方案。
% No siempre da soluciones, se suele quedar estancado con muy pocos jaques
% por población.
clc, clear
% Parámetros y vectores iniciales
N = 10000; % Número de iteraciones
n = 8; % Número de reinas
l = 8; % Longitud de cada lado del tablero
% Condición para que no haya más reinas que lados del tablero
while n > l
n = n-1;
end
pob = 5; % Número de población
f = @(x) n*l - x; % Función de aptitud, entre mayor cantidad de jaques, menor será la puntuación.
tableros = cell(1,pob+2); % Celda en donde se guardarán los vectores de cada población
posiciones = cell(1,pob+2);
hijo1 = zeros(n,2);
hijo2 = zeros(n,2);
hijo1(1:n,1) = 0:n-1;
hijo2 = hijo1;
[posiciones_iniciales, tableros_iniciales, cont_jaques, puntuacion] = pob_inicial(pob, n, l, f);
posiciones = posiciones_iniciales;
% Padres
[valoresMayores, padres] = mink(cont_jaques,2);
cont = 1;
resultado = 0;
while cont ~= N
pc = randi([1,n]); % Punto de cruzamiento
hijo1 = posiciones{padres(1)};
hijo2 = posiciones{padres(2)};
hijo1(pc+1:n,2) = posiciones{padres(2)}(pc+1:n,2);
hijo2(pc+1:n,2) = posiciones{padres(1)}(pc+1:n,2);
if rand > 0.2 % Probabilidad de mutación del 80% del hijo 1
m = randi([1,n]);
hijo1(m, 2) = randi([0,n-1]);
end
if rand > 0.2 % Probabilidad de mutación del 80% del hijo 1
m = randi([1,n]);
hijo2(m, 2) = randi([0,n-1]);
end
posiciones{pob + 1} = hijo1;
posiciones{pob + 2} = hijo2;
% Posiciones de los tableros (para el cálculo de los jaques)
for ii = 1:pob+2
tableros{ii} = zeros(l,l); % Tablero (si en la casilla hay un 1, significa que en esa posición hay una reina)
for k = 1:n
tableros{ii}(posiciones{ii}(k,1)+1, posiciones{ii}(k,2)+1) = 1;
end
% Checar los jaques de los tableros iniciales
n_jaques = jaques(posiciones{ii}(:,2)', l, ii, tableros);
cont_jaques(ii) = n_jaques;
% Prueba de aptitud
puntuacion(ii) = f(cont_jaques(ii));
end
% Eliminados (los de menor aptitud)
[valoresMenores, eliminados] = maxk(cont_jaques, 2);
posiciones(:, eliminados) = [];
cont_jaques(eliminados) = [];
puntuacion(eliminados) = [];
% Padres
[valoresMayores, padres] = mink(cont_jaques, 2);
% Checar si hay soluciones
for jj = 1:pob
if cont_jaques(jj) == 0
resultado = 1;
break
end
end
if resultado == 1
break
else
cont = cont + 1;
end
end
if cont == N
fprintf('No se ha encontrado solución en %d iteraciones. \n', N)
else
fprintf('Se encontró la solución despues de %d iteraciones. \n', cont)
end
for ii = 1:pob
if cont_jaques(ii) == 0
subplot(2, 3, 2)
tablero(l)
title('Tablero inicial', ii)
reinas(posiciones_iniciales{ii}(:,1),posiciones_iniciales{ii}(:,2), n, 'red')
subplot(2, 3, 5)
tablero(l)
title('Tablero final', ii)
reinas(posiciones{ii}(:,1),posiciones{ii}(:,2), n, 'green')
end
end
%% Función que genera las poblaciones iniciales aleatoriamente
function [posiciones_iniciales, tableros_iniciales, cont_jaques, puntuacion] = pob_inicial(pob, n, l, f)
% pob: Número de población
% n: Número de reinas
% l: Lado del tablero
% f: Función de aptitud
tableros_iniciales = cell(1,pob); % Celda en donde se guardarán los vectores de cada población
posiciones_iniciales = cell(1,pob); % Celda en donde se guardarán los vectores de cada población
cont_jaques = zeros(1,pob); % Vector de contador de jaques de cada tablero
puntuacion = zeros(1,pob); % Vector que guarda las puntuaciones de aptitud
for ii = 1:pob
% Poblaciones iniciales aleatorias
r = randi([0,l-1],1,n);
for jj = 0:n-1
posiciones_iniciales{ii}(jj+1,1) = jj;
posiciones_iniciales{ii}(jj+1,2) = r(jj+1);
end
% Posiciones del tablero
tableros_iniciales{ii} = zeros(l,l); % Tablero (si en la casilla hay un 1, significa que en esa posición hay una reina)
for k = 1:n
tableros_iniciales{ii}(posiciones_iniciales{ii}(k,1)+1, posiciones_iniciales{ii}(k,2)+1) = 1;
end
% Checar los jaques de los tableros iniciales
n_jaques = jaques(posiciones_iniciales{ii}(:,2), l, ii, tableros_iniciales);
cont_jaques(ii) = n_jaques;
% Prueba de aptitud
puntuacion(ii) = f(cont_jaques(ii));
end
end
%% Función de comprobación de jaques
function n_jaques = jaques(ry, l, n_tablero, celda_tableros)
% Función que comprueba cuántas reinas hay en jaque dado un tablero
n_jaques = 0;
% Verticales
By = unique(ry);
n_repetidos_y = histc(ry, By);
c_unicos_y = size(n_repetidos_y);
for jj = 1:c_unicos_y(2)
if n_repetidos_y(jj) > 1
combinatoria_y = factorial(n_repetidos_y(jj))/(factorial(n_repetidos_y(jj) - 2));
n_jaques = n_jaques + combinatoria_y; % Se suman la cantidad de jaques posibles de la columna
end
end
% Diagonales con pendiente negativa
for k = 0:l
% Diagonales con k positiva
diagonal1 = diag(celda_tableros{n_tablero},k);
n_reinas_d1 = numel(find(diagonal1==1));
if n_reinas_d1 == 2
n_jaques = n_jaques + 1;
elseif n_reinas_d1 > 2
combinatoria_d1 = factorial(n_reinas_d1)/(factorial(2)*(factorial(n_reinas_d1 - 2)));
n_jaques = n_jaques + combinatoria_d1;
end
% Diagonales con k negativa
end
for k = -1:-1:-l
diagonal2 = diag(celda_tableros{n_tablero},k);
n_reinas_d2 = numel(find(diagonal2==1));
if n_reinas_d2 == 2
n_jaques = n_jaques + 1;
elseif n_reinas_d2 > 2
combinatoria_d2 = factorial(n_reinas_d2)/(factorial(2)*(factorial(n_reinas_d2 - 2)));
n_jaques = n_jaques + combinatoria_d2;
end
end
% Diagonales con pendiente positiva
for k = 0:l
% Diagonales con k positiva
diagonal1 = diag(fliplr(celda_tableros{n_tablero}),k);
n_reinas_d1 = numel(find(diagonal1==1));
if n_reinas_d1 == 2
n_jaques = n_jaques + 1;
elseif n_reinas_d1 > 2
combinatoria_d1 = factorial(n_reinas_d1)/(factorial(2)*(factorial(n_reinas_d1 - 2)));
n_jaques = n_jaques + combinatoria_d1;
end
% Diagonales con k negativa
end
for k = -1:-1:-l
diagonal2 = diag(fliplr(celda_tableros{n_tablero}),k);
n_reinas_d2 = numel(find(diagonal2==1));
if n_reinas_d2 == 2
n_jaques = n_jaques + 1;
elseif n_reinas_d2 > 2
combinatoria_d2 = factorial(n_reinas_d2)/(factorial(2)*(factorial(n_reinas_d2 - 2)));
n_jaques = n_jaques + combinatoria_d2;
end
end
end
%% Función de gráfica del tablero
function tablero(l)
% Función que crea un tablero de lado l
x1=0; x2=l;
y1=0; y2=l;
x = [x1, x2, x2, x1, x1];
y = [y1, y1, y2, y2, y1];
plot(x, y, 'k-', 'LineWidth', 1.5);
hold on
xlim([-1, l+1]);
ylim([-1, l+1]);
% Grid
for i = 1:l
plot([0,l],[i,i], 'k-', 'LineWidth', 1.5)
plot([i,i],[0,l],'k-', 'LineWidth', 1.5)
end
end
%% Función de gráfica de las reinas
function reinas(rx,ry,n,color)
% Función que grafica n cantidad de reinas en las posiciones en x y y dadas por los vectores rx y ry.
for n = 1:n
g_reinas = plot(rx(n)+0.5,ry(n)+0.5, 'or');
g_reinas.MarkerFaceColor = [color];
g_reinas.MarkerSize = 6;
g_reinas.MarkerEdgeColor = [color];
% legend(reinas,'Reinas')
end
hold off
end
1条答案
按热度按时间35g0bw711#
也许使用随机函数查找所有总体并不能让您快速找到所有解。
您可以搜索列索引的所有可能排列n!,列索引的不同排列的示例是(1.5.8.6.3.7.2.4)和(1.6.8.3.7.4.2.5),在第一种情况下,它们对应于皇后(1,1)的位置;(二、五);(三、八);(四、六);(五、三);(六、七);(七、二);(8、4)。
或者使用像这样的优化解决方案,它不评估所有排列,但在满足某些条件时会进行跳跃。
此代码已通过SCILAB测试,但也可在MATLAB中运行: