用遗传算法解八皇后问题

此算法收敛速度还可以,基本在1万代之内就能找到解

主程序

clear;
clc;

%%
%八皇后问题,8X8的棋盘上,放置8个皇后,使之两两都不能攻击
%初始的状态,随机在棋盘上放置8个皇后,每列放一个
n = 8; %8皇后

%%
    %用遗传算法计算
    %先随机获得几个个体,形成一个种群
    %这个种群有10个个体
    No_of_people = 10;
    people = randi(n,[No_of_people,n]);
    
    %计算每个初始种群的h值
    people_h = ones(No_of_people,1);
    for i = 1:No_of_people
        people_h(i) = fun_c(people(i,:));
    end
        
    %进化了多少代,由G来统计
    G = 1;
    G_max = 1e5;
    plt = zeros(1,G_max);
    while prod(people_h)~=0 && G<=G_max
        %精英保留策略,保留初始种群中1/100的精英个体 
        %保留多少个精英
        No_elite = fix(No_of_people/100);
        if No_elite == 0
            No_elite =1;
        end
        
        %按照h值选出这些精英
        [~,ind] = sort(people_h);
        index = ind(1:No_elite);
        people_elite = people(index,:);
               
        %计算这个种群中每个个体的优势,以百分比表示,所有个体优势之和为1
        adv = people_h ./ sum(people_h);
        
        %从种群中随机选出10对个体,根据个体的优势来选择,优势越大的,被选中的概率越大
        people_dad = people;
        people_mom = people;
        for i=1:No_of_people
            pick = ones(2,1);
            while pick(1)==pick(2)
                pick = randsrc(2,1,[1:No_of_people; adv']);
            end
            people_dad(i,:) = people(pick(1),:);
            people_mom(i,:) = people(pick(2),:);
        end
        
        %然后交叉繁殖,染色体交叉。一对夫妇只生一个孩子
        for i=1:No_of_people
            %随机生成一个交叉位点
            p = randi(n-1);
            people(i,:) = [people_dad(i,1:p),people_mom(i,p+1:n)];
        end
        
        %然后以一定的概率,产生随机突变
        for i=1:No_of_people
            %随机生成一个突变位点
            p_change = rand(1);
            p_dot = randi(n);
            %设定突变的概率为10%
            if p_change <= 0.1 
                  people(i,p_dot) = randi(n);
            end
        end
        
        %更新种群的h值
        for i = 1:No_of_people
             people_h(i) = fun_c(people(i,:));
        end
        
        %找出繁殖的后代中最差的个体,个体数量 = 精英数量
        [~,ind] = sort(people_h,'descend');
        index_bad = ind(1:No_elite);
        %删除最差的个体
        people(index_bad,:) = [];
                
        %把精英加入种群
        people_tmp = [people; people_elite];
        people = people_tmp;
       
        %更新种群的h值
        for i = 1:No_of_people
             people_h(i) = fun_c(people(i,:));
        end
        
        plt(G) = min(people_h);
        G = G + 1;
                        
    end
    
    plot(plt(1:G-1));
    axis auto;
        
%%
    if prod(people_h)==0
        disp('遗传算法收敛');
        index = find(people_h == 0);
        disp('可能的解为 ');
        disp(people(index,:));
    else
        disp('遗传算法不收敛');
    end
    disp(['经历了 ',num2str(G-1),' 代遗传']);

 

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

 

    原文作者:八皇后问题
    原文地址: https://www.cnblogs.com/shekarry/p/5369922.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞