用遺傳算法解八皇后問題


此算法收斂速度還可以,基本在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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM