遗传算法求解八皇后问题—matlab

题目要求

在8*8的国际象棋棋盘上放置了八个皇后,要求没有一个皇后能攻击另一个皇后,即任意两个皇后都不处于棋盘的同一行、同一列或同一对角线上。要求设计并实现解决八皇后问题的遗传算法。

设计思路

遗传算法是模拟自然选择和遗传学机理的生物进化过程的一种计算模型,主要特点为直接对结构对象进行操作,无需求导和对函数连续性的限定,具有较好的并行性和全局寻优能力。
染色体编码方案适应度函数的设计遗传操作(选择、交叉、变异)的设计控制参数的设定,是遗传算法的核心问题,所以需要针对八皇后问题建立适合遗传算法的模型。

1.染色体编码

可以将8*8棋盘看作一个8行8列的矩阵,以行向量为染色体,每位基因值为该列上棋子所处的行值,即可表征所有棋子的位置。如图1所示,染色体population=[5,8,4,1,7,8,6,3]。
棋盘编码染色体实例

在遗传算法开始时种群存在多个个体,就可以将其组合起来。若种群个体数量为n,则可以形成一个n*8的矩阵,每一行即为每个个体的染色体。

2.适应度函数

遗传算法中的适应度函数即为对最优解的要求。那针对八皇后问题,则是需要得到互不攻击的一种棋子摆放情况,其中攻击包括:列攻击,行攻击,主对角线攻击,副对角线攻击。
(1)列攻击:由于在染色体的编码为行向量,那么每一位只能存放一个数据,所以默认所有个体都不会产生列攻击。
(2)行攻击:当染色体行向量中,存在某两位或更多位的值相同时,即存在互相攻击情况。
(3)主对角线攻击:当染色体行向量中,存在某两位或更多为的下标之差等于对应下标的值之差时,即两者间斜率为1,即存在互相攻击情况。
(4)副对角线攻击:当染色体行向量中,存在某两位或更多为的下标之差等于对应下标的值之差的负值时,即两者间斜率为-1,即存在互相攻击情况。
当上述攻击每发生一次时,适应度函数加1。因此在本例中与传统遗传算法相反,一个个体的适应度越大代表这个解越差,只有适应度为0时才是符合要求的解,所以也可以将本例中的适应度理解为攻击度,即攻击度越小越好。

3.选择算子

遗传算法中的选择是为了从种群中选择出满足要求的个体,以便得到更优秀的后代。在本次设计中,采用了轮盘赌的选择方式。但需要注意的是,上述的适应度计算方案让最优秀个体的值反而最小,因此在轮盘赌算法时,优秀的个体所占的区域反而更小。所以,设定一个最大值max,在轮盘赌时用最大值减去适应度值fit_population,得到一个个体越优秀值越大的轮盘适应度wheel_fit。互相不攻击的最大值max为 n*(n-1)/2,本例中即为28。所以wheel_fit = 28 - fit_population
每次轮盘赌根据生成的随机数选择出两组较为优秀的个体,进入后续的交叉繁衍。

4.交叉算子

遗传算法中的交叉是为了在整体解空间中尝试更多的组合情况。因此本次设计中采用映射交叉算子,即随机生成交叉点,对上一步选择出的父代和母代染色体进行映射互换。

5.变异算子

遗传算法中的变异是为了使其具备局部的随机搜索能力。本次设计中采用的均匀变异算子,即用符合编码范围内的随机数,以某一较小概率来替换染色体上某一位的基因值。本次设计的变异发生平均概率设定为10%。

6.精英替换

为优化寻优算法,加速收敛过程,本次设计采用了精英替换策略,首先在每次繁衍开始时挑选精英个体,然后在每次遗传操作完成后,淘汰此时最差的个体并由精英个体进行替换。本次设计的精英替换数量设定为1。

运行结果

连续运行设计程序十次,最大迭代次数8949次,最小迭代次数731次,平均迭代次数约为4140次,均能得到符合要求的解。
运行结果
运行过程

源程序

%遗传算法求解八皇后问题
clear;
clc;
n = 8;  %棋盘大小为 n*n
num_population = 10;  %这个种群有10个个体
population = randi(n,[num_population,n]);  %生成种群初始染色体
G = 1;
G_max = 1e5;  %繁衍上限
generation = zeros(1,G_max);

%计算每个初始种群的适应度
fit_population = ones(num_population,1);
for i = 1:num_population
    fit_population(i) = GA_fitness(population(i,:));
end    

while prod(fit_population)~=0 && G<=G_max    %循环直到找到解或超过繁衍上限
    elite = 1;      %每次繁衍种群更新量
    
    %按照适应度选出精英
    [~,index] = sort(fit_population);  %升序排列后,每个适应度在原列表的位置
    order = index(1:elite);            
    elite_population = population(order,:);  %得到精英染色体
    
    %轮盘赌选择新种群
    max = 28*ones(num_population,1);
    wheel_fit = max - fit_population;
    pro_fit = wheel_fit ./ sum(fit_population);
    
    pro_wheel1 = rand(10,1);  %生成随机概率
    pro_wheel2 = rand(10,1);
    father = GA_selection(pro_fit,population,pro_wheel1);
    mother = GA_selection(pro_fit,population,pro_wheel2);

    %随机生成交叉位置,染色体交叉繁衍
    for i=1:num_population
        cross = randi(n-1);
        population(i,:) = [father(i,1:cross),mother(i,cross+1:n)];
    end

    %染色体随机变异
    for i=1:num_population
        mu_pro = rand(1);
        mu_location = randi(n);
        if mu_pro <= 0.1
              population(i,mu_location) = randi(n);
        end
    end

    %更新种群的适应度
    for i = 1:num_population
         fit_population(i) = GA_fitness(population(i,:));
    end

    %找出繁殖的后代中最差的个体,把精英加入种群
    [~,index] = sort(fit_population,'descend');
    index_bad = index(1:elite);
    population(index_bad,:) = [];    %删除最差的个体
    population_temp = [population; elite_population];
    population = population_temp;

    %更新种群的适应度
    for i = 1:num_population
         fit_population(i) = GA_fitness(population(i,:));
    end

    generation(G) = min(fit_population);
    G = G + 1;
end
plot(generation(1:G-1));
title('遗传算法最优解迭代过程');
legend('最优种群适应度值');
xlabel('迭代次数');
ylabel('适应度值');
axis auto;
if prod(fit_population)==0
    disp('遗传算法收敛');
    order = find(fit_population == 0);
    disp('可能的解为 ');
    disp(population(order,:));
else
    disp('遗传算法不收敛');
end
disp(['经历了 ',num2str(G-1),' 代遗传']);

function [fitness] = GA_fitness(state)
    %适应度计算函数
    %输入是种群中个体的染色体
    fitness = 0; 
    n = length(state);   

    %每列的状态,看有多少个能互相攻击,每两两攻击算一次 先算行攻击
    for j=1:n
        for k=(j+1):n
            if state(j)==state(k)
                fitness = fitness + 1;
            end  
            if state(j)-state(k) == j-k || state(j)-state(k) == k-j 
                fitness = fitness + 1;
            end         
        end
    end
     
end

function [ selection ] = GA_selection( pro_fitness , population , wheel )
% 父母代选择函数
% 输入分别是 归一化的适应度,种群,概率轮盘
    num_population = 10;  
    selection = population; %初始化父母代
    pro_array = cumsum(pro_fitness);
  
    for i=1:num_population
        k=1;
        while k <= num_population
            if wheel(i) < pro_array(k)
                selection(i,:) = population(k,:);
                break;
            else
                k = k + 1;
            end
        end
    end
end

  • 8
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值