zoukankan      html  css  js  c++  java
  • 八皇后问题遗传算法实现(python版)

    八皇后问题的遗传算法实现过程详解

     

    1、八皇后问题描述
    19 世纪著名的数学家Gauss 在1850 年提出八皇后问题后, 该问题成为各类语言程序设计的经典题目。八皇后问题要求在8×8 格的国际象棋上摆放八个皇后,使横、竖、斜方向上都不能有两个及两个以上皇后在同一条直线上, 问题也可以推广到N 个皇后。穷举法在问题规模不大的情况下还可适用,回溯法是求解此问题的经典算法。但N 皇后问题是个NP 难问题, 随着皇后数目的增多, 求解复杂度激增, 就需利用非常规的技术求解。遗传算法在求解一些NP 完全问题上得到了广泛地应用,本文用遗传算法求解八皇后问题,给出详细的实现过程。


    2、基本遗传算法求解过程
     基本遗传以初始种群为基点, 经过选择、交叉、变异操作生成新的种群,如此更新种群直到满足终止条件。其计算步骤如下:
    (1) 将问题空间转换为遗传空间, 也就是编码;
    (2)随机生成P 个染色体作为初始种群;
    (3)染色体评价,也就是按确定的适应度函数
    计算各个染色体的适应度;
    (4)根据染色体适应度,按选择算子进行染色体的选择;
    (5)按交叉概率进行交叉操作;
    (6)按变异概率进行变异操作;
    (7)返回(4)形成新的种群,继续迭代,直到满足终止条件。

    基本遗传算法给出了基本框架, 针对求解的问题不同, 遗传算法在相应的计算步骤中有不同的设计。本文针对八皇后问题, 设计了相应的编码,适应度计算方法,交叉和变异操作。

     

    3、用遗传算法求解八皇后问题实现过程详解

     

    3.1 编码
    遗传算法中传统的编码是二进制编码, 本文采用多值编码。染色体长度取决于皇后的个数。染色体中每个基因所处的位置表示其在棋谱中所在的行数, 基因值表示其所在的列数。如染色体40752613 表示:从0 开始数,第0 个4 表示在第零行的皇后在第4 列, 第1 个0 表示第一行的皇后在第0 列,以此类推。八皇后问题中皇后不能处于同行同列, 意味着染色体中0~7 的基因取值不能出现重复。

     

    3.2 个体评价
    染色体通常表示了问题的可行解, 对可行解进行遗传操作寻找最优解。但在八皇后问题中,染色体仅仅体现同行同列中未出现互攻, 在对角线上是否出现互攻还未做考虑。在对皇后的位置做比较的时候, 可以对两个棋子的行数差与列数差进行对比, 实现了互攻次数的统计。公式为:|绝对值((y2-y1)/(x2-x1)) |=1。公式中(x1,y1),(x2,y2)分别表示两个皇后所在的位置,即所在的行数和列数。当两个皇后的行数差与列数差比值的绝对值为1 的时候,两皇后在同一对角线上,即出现了互攻。每个染色体内的互攻次数为Value,初始值设为0;第0 行与1~7 行进行比较, 每出现一次互攻则Value 的值增加1;第1 行与2~7 行进行比较,以此类推来计算Value 值。当Value 为0 表示没有发生互攻,此染色体就是其中的一个可行解。当Value 不为0则进行适应度的计算。一般来说, 适应度越大越
    好,而互攻次数为越小越好,所以可以将适应度的计算函数设置为:F=28-Value。

     

    3.3 选择
    选择使用的是经典的赌轮选择方法, 与基本遗传算法的实现无特别之处,此处不赘述。

     

    3.4 交叉

    经典的单点, 多点等交叉因染色体中不能出现重复的基因值,在该问题中不适用。本文使用部分匹配交叉,具体操作如下:


    1)在染色体中随机选取两个点标记为y,

    如:染色体a:01y24y3675;

    染色体b:12y30y4576;

    两个y 之间的基因段称为中间段, 记录其对应关系2-3,4-0;


    2)对染色体a,b 的中间段进行交换,

    形成染色体a':01y30y3675;染色体b': 12y24y4576;

    3) 利用对应关系,对染色体a', b' 中间段外的基因进行交换,

    形成 染色体a'': 41y30y2675;

    染色体b'':   13y24y0576;

    交叉完成。

     

    3.5 变异
    采用多值编码后, 变异操作并不能通过简单的0,1 反转实现。

    本文采取随机地选取染色体内的两个基因进行交换来实现。

    例如随机选取的是
    6 和1 两个基因,那么
    变异前染色体: 7 (6) 5 4 3 2 (1) 0
    变异后染色体: 7 (1) 5 4 3 2 (6) 0

     

    3.6 终止策略
    本文采用的终止策略为: 当群体中出现染色体的适应值为0 时, 即表示算法搜索到了一个可行解,终止算法。若算法运行设置的代数还未找到可行解,同样终止程序运行。

     

    4、总结
    本文详细介绍了用遗传算法求解八皇后问题的求解过程, 但要注意的是这只是其中的一种编码,交叉,变异等操作设计方法,还有许多其他的方法可以选择。对于各操作采取不同设计方案的遗传算法,其算法性能值得比较讨论。

     

     

      1 #
      2 #   遗传算法(八皇后问题)
      3 #   最佳值28
      4 import random
      5 import numpy
      6 
      7 
      8 N=8  #皇后数
      9 Cluster_size=12   #默认种群大小
     10 LASTG=100    #/*终止后代*/
     11 MRATE=0.8  #/*突变的概率*/
     12 array=numpy.zeros((Cluster_size,N)).astype(int) #染色体集合
     13 narray=numpy.zeros((Cluster_size * 2,N)).astype(int) #下一代染色体集合
     14 _array=numpy.zeros((Cluster_size,N)).astype(int)#array数组的副本
     15 values=numpy.zeros(Cluster_size).astype(int) #评估数组
     16 max_array=numpy.zeros(N).astype(int) #保存最佳数组
     17 generation = 0 #记录代数
     18 signal = -1   # 信号
     19 max = -1 # 记录当前最优值
     20 max_generation = -1  #记录当前最优值代数
     21 
     22 
     23 
     24 class Struct:
     25     key = numpy.zeros(N).astype(int)
     26     values = numpy.zeros(N).astype(int)
     27 
     28 
     29 rember=Struct()
     30 
     31 
     32 def rndn(l):
     33     rndno =random.randint(0,l-1)
     34     return rndno
     35 
     36 
     37 def copy_array():
     38     for i in range(Cluster_size):
     39         for j in range(N):
     40             _array[i][j]=array[i][j]
     41 
     42 
     43 def output_copy_array():
     44     for i in range(Cluster_size):
     45         for j in range(N):
     46             print(_array[i][j],end=" ")
     47         print()
     48 
     49 
     50 def the_answer(values,size):
     51     for i in range(size):
     52         if values[i]==28:
     53             return i
     54     return -1
     55 
     56 
     57 def judge(a,n):
     58     value = -1
     59     for i in range(n):
     60         value = a[i]
     61         j=i+1
     62         while j<n:
     63             if(value==a[j]):
     64                 return 0
     65             j+=1
     66     return 1
     67 
     68 
     69 
     70 def count_collidecount():
     71     value=0
     72     global signal
     73     for i in range(Cluster_size):
     74         for j in range(N):
     75             x1=j
     76             y1=array[i][j]
     77             m=j+1
     78             while m<N:
     79                 x2=m
     80                 y2=array[i][m]
     81                 if (abs((y2-y1)/(x2-x1))==1):
     82                     value+=1
     83                 m+=1
     84         values[i]=28-value
     85         value=0
     86     signal= the_answer(values,Cluster_size)
     87 
     88 
     89 
     90 def count_generation_collidecount(values,cluster_size):
     91     value=0
     92     for i in range(cluster_size):
     93         for j in range(N):
     94             x1=j
     95             y1=narray[i][j]
     96             m=j+1
     97             while m<N:
     98                 x2=m
     99                 y2=narray[i][m]
    100                 if(abs((y2 - y1) / (x2 - x1))==1):
    101                     value+=1
    102                 m+=1
    103         values[i]=28-value
    104         value=0
    105 
    106 
    107 # /************************/
    108 # /*   selectp()函数      */
    109 # /*    父代的选择        */
    110 # /************************/
    111 def selectp(roulette,totalfitness):
    112     acc=0
    113     ball=rndn(totalfitness)
    114     for i in range(Cluster_size):
    115         acc+=roulette[i]
    116         if (acc>ball):
    117             break
    118     return i
    119 
    120 
    121 def  takeoutrepeat( position):
    122     signal=True
    123     for i in range(N):
    124         value = narray[position*2][i]
    125         j=i+1
    126         while j<N:
    127             if (narray[position*2][j]==value):
    128                 # print("there have reapt number: "+str(position*2))
    129                 signal=False
    130             j+=1
    131     for i in range(N):
    132         value=narray[position*2+1][i]
    133         j=i+1
    134         while j<N:
    135             if (narray[position*2+1][j]==value):
    136                 # print("there have reapt number: "+str(position*2+1))
    137                 signal=False
    138             j+=1
    139     return signal
    140 
    141 
    142 
    143 
    144 def judge_reapt(c, cluster):
    145     value =0
    146     arraysEqual =True
    147     i=0
    148     for j in range(cluster):
    149         while (arraysEqual and i<N):
    150             if (narray[c][i] !=_array[j][i]):
    151                 arraysEqual=False
    152             i+=1
    153         if(arraysEqual):
    154             value+=1
    155         else:
    156             arraysEqual=True
    157         i=0
    158 
    159     if(value>0):
    160         return False
    161     else:
    162         return True
    163 
    164 
    165 
    166 
    167 # /************************/
    168 #  /*   selection()函数      */
    169 #  /*   选择下一代          */
    170 #  /************************
    171 
    172 def selection():
    173     global signal
    174     global max_generation
    175     global max
    176     totalfitness=0
    177     roulette=numpy.zeros(Cluster_size*2).astype(int)
    178     acc=0
    179     for i in range(Cluster_size):
    180         totalfitness=0
    181         count_generation_collidecount(roulette,Cluster_size*2)
    182         c=0
    183         while c<Cluster_size*2:
    184             totalfitness+=roulette[c]
    185             c+=1
    186         signal=the_answer(roulette,Cluster_size*2)
    187 
    188         while True:
    189             ball =rndn(totalfitness)
    190             acc=0
    191             c=0
    192             while c<Cluster_size*2:
    193                 acc+=roulette[c]
    194                 if acc>ball:
    195                     break
    196                 c+=1
    197             judge=judge_reapt(c,Cluster_size)
    198             if judge==True:
    199                 break
    200         #/ *染色体的复制 * /
    201         for j in range(N):
    202             array[i][j]=narray[c][j]
    203 
    204     for q in range(Cluster_size*2):
    205         if roulette[q]>max:
    206             max =roulette[q]
    207             max_generation = generation
    208             for i in range(N):
    209                 max_array[i]=narray[q][i]
    210         print(roulette[q], end=" ")
    211     print()
    212 
    213 
    214 
    215 
    216 
    217 
    218 def judgein(m,location1,location2):
    219     i=location1
    220     while i<=location2:
    221         if ((m == rember.key[i]) | (m == rember.values[i])):
    222             return i
    223         i+=1
    224     return -1
    225 
    226 
    227 
    228 
    229 
    230 
    231  # /************************/
    232  # /*  crossing()函数      */
    233  # /* 特定2染色体的交叉    */
    234  # /************************/
    235 def crossing(mama, papa,position):
    236     while True:
    237         while True:
    238             cp1 = rndn(N)
    239             cp2 = rndn(N)
    240             if cp1 != cp2:
    241                 break
    242         # print("cp1="+str(cp1)+"cp2="+str(cp2))
    243         if cp1<cp2:
    244             location1 = cp1
    245             location2 = cp2
    246         else:
    247             location1 = cp2
    248             location2 = cp1
    249 
    250         i = location1
    251         while i<=location2:
    252             rember.key[i] = array[mama][i]
    253             rember.values[i] = array[papa][i]
    254             # 交换中间段
    255             narray[position*2][i] = array[papa][i]
    256             narray[position*2+1][i] = array[mama][i]
    257             i+=1
    258         # 利用对应关系,对染色体mama和papa, 中间段外的基因进行交换
    259             #/ * 交换前半部分 * /
    260         for j in range(location1):
    261             weizhi = judgein(array[mama][j],location1,location2)
    262             # print("weizhi= "+str(weizhi))
    263             if (weizhi == -1):
    264                 narray[position*2][j] = array[mama][j]
    265             else:
    266                 if (array[mama][j] == rember.key[weizhi]):
    267                     narray[position*2][j] = rember.values[weizhi]
    268                 else:
    269                     narray[position*2][j] = rember.key[weizhi]
    270             weizhi = judgein(array[papa][j], location1, location2)
    271             if (weizhi == -1):
    272                 narray[position*2+1][j] = array[papa][j]
    273             else:
    274                 if (array[papa][j] == rember.key[weizhi]):
    275                     narray[position*2+1][j] = rember.values[weizhi]
    276                 else:
    277                     narray[position*2+1][j] = rember.key[weizhi]
    278 
    279 
    280          #/ *交换后半部分 * /
    281         j = location2+1
    282         while j<N:
    283             weizhi = judgein(array[mama][j], location1, location2)
    284             if (weizhi == -1):
    285                 narray[position*2][j] = array[mama][j]
    286             else:
    287                 if (array[mama][j] == rember.key[weizhi]):
    288                     narray[position*2][j] = rember.values[weizhi]
    289                 else:
    290                     narray[position*2][j] = rember.key[weizhi]
    291             weizhi = judgein(array[papa][j],location1,location2)
    292             if (weizhi == -1):
    293                 narray[position*2+1][j] = array[papa][j]
    294             else:
    295                 if (array[papa][j] == rember.key[weizhi]):
    296                     narray[position*2+1][j] = rember.values[weizhi]
    297                 else:
    298                     narray[position*2+1][j] = rember.key[weizhi]
    299             j+=1
    300 
    301         signal = takeoutrepeat(position)
    302         # print("--------------signal= "+str(signal))
    303         if (signal != False):
    304            break
    305 
    306 
    307 
    308 
    309 
    310 
    311         # /************************/
    312  # /*   notval()函数       */
    313  # /*                      */
    314  # /************************/
    315 def notval(i):
    316     while True:
    317         position1 =rndn(N)
    318         position2 =rndn(N)
    319         if position1 != position2:
    320             break
    321     temp=narray[i][position2]
    322     narray[i][position2] = narray[i][position1]
    323     narray[i][position1] =temp
    324 
    325 
    326 
    327 
    328 #  /***********************/
    329 # /*   mutation()函数    */
    330 #  /*   突变              */
    331 #  /***********************/
    332 def mutation():
    333     for i in range(Cluster_size*2):
    334         if (rndn(100) / 100 <= MRATE):
    335             #/ *染色体突变 * /
    336              notval(i)
    337     print("mutation is complete")
    338 
    339 
    340 
    341 
    342 
    343 def mating():
    344     totalfitness =0
    345     roulette=numpy.zeros(Cluster_size).astype(int)
    346     print(len(roulette))
    347      # 生成轮盘
    348     for i in range(Cluster_size):
    349         roulette[i] = values[i]
    350         totalfitness += roulette[i]
    351     #  选择和交叉的循环
    352     for i in range(Cluster_size):
    353         while True:
    354             mama=selectp(roulette,totalfitness)
    355             papa=selectp(roulette,totalfitness)
    356             if mama != papa:
    357                 break
    358         # 特定2染色体的交叉
    359         crossing(mama,papa,i)
    360 
    361 
    362 
    363 def outputrember():
    364     for i in range(N):
    365         print("key= "+rember.key[i]+"values= "+rember.values[i])
    366 
    367 
    368 
    369 
    370 def outputnarray():
    371     for i in range(Cluster_size*2):
    372         if (i % 2 ==0):
    373             print("------------------------------")
    374         for j in range(N):
    375             print(narray[i][j],end=" ")
    376         print()
    377 
    378 
    379 
    380 
    381 def output():
    382     global max
    383     global max_generation
    384     for i in range(Cluster_size):
    385         if values[i]>max:
    386             max =values[i]
    387             max_generation=max_generation
    388         print(values[i],end=" ")
    389     print()
    390 
    391 
    392 
    393 
    394 def outputarray():
    395     for i in range(Cluster_size):
    396         for j in range(8):
    397             print(array[i][j], end =" ")
    398         print()
    399 
    400 
    401 
    402 
    403 
    404 def init_Cluster():
    405     print('fsadsgagasgs')
    406     a=[0 for n in range(8)]
    407     count=0
    408     while count < Cluster_size:
    409          for y in range(8):
    410              x= random.randint(0,7)  #产生0到7的随机数
    411              a[y]=x
    412          if(judge(a,8)):
    413              for i in range(8):
    414                  array[count][i]=a[i]
    415          else:
    416              count=count-1
    417          count+=1
    418 
    419 
    420 
    421 
    422 
    423 def main():
    424     global generation
    425     init_Cluster()
    426     while generation<LASTG:
    427         if signal!=-1:
    428             break
    429         else:
    430             print("代数= "+str(generation))
    431             count_collidecount()
    432             print("-------------output------------values--------------------------")
    433             output()
    434             print("------------- outputarray--------------------------------------")
    435             outputarray()
    436             mating()
    437             print("------------- outputarray--------------------------------------")
    438             outputarray()
    439             print("-----------------mating选择交叉---------outputnarray---------------")
    440             outputnarray()
    441             mutation()
    442             print("-----------------mutation变异---------outputnarray---------------")
    443             outputnarray()
    444             print("------------- outputarray--------------------------------------")
    445             outputarray()
    446             copy_array()
    447             # print("---------------------------------------------------------------")
    448             # output_copy_array()
    449             selection()
    450             print("-----------------selection选择下一代--------outputarray---------------")
    451             outputarray()
    452         generation+=1
    453     print("signal = "+str(signal)+" max ="+str(max)+" max_generation = "+str(max_generation)) #max为最佳值, max_generation为产生最佳值的代数
    454     print(max_array,end=" ")
    455 
    456 
    457 if __name__ == "__main__":
    458     main()

     

     

     

  • 相关阅读:
    access denied for user 'root'@'localhost'(using password:YES) FOR WINDOWS
    PKU 1001解题代码
    PKU 1002解题总结
    为什么vue组件data必须是函数
    call 和 apply 区别
    CSS|Stacking context 堆叠上下文
    Vue3.0 tsx 函数组件
    js中的变量提升
    JavaEE|架构
    MVC,MVP 和 MVVM
  • 原文地址:https://www.cnblogs.com/liweikuan/p/14103482.html
Copyright © 2011-2022 走看看