1. 程式人生 > 實用技巧 >八皇后問題遺傳演算法實現(python版)

八皇后問題遺傳演算法實現(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=1/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 #
  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     for i in range(Cluster_size):
383         # if values[i]>max:
384         #     max =values[i]
385         #     max_generation=max_generation
386         print(values[i],end=" ")
387     print()
388 
389 
390 
391 
392 def outputarray():
393     for i in range(Cluster_size):
394         for j in range(8):
395             print(array[i][j], end =" ")
396         print()
397 
398 
399 
400 
401 
402 def init_Cluster():
403     print('fsadsgagasgs')
404     a=[0 for n in range(8)]
405     count=0
406     while count < Cluster_size:
407          for y in range(8):
408              x= random.randint(0,7)  #產生0到7的隨機數
409              a[y]=x
410          if(judge(a,8)):
411              for i in range(8):
412                  array[count][i]=a[i]
413          else:
414              count=count-1
415          count+=1
416 
417 
418 
419 
420 
421 def main():
422     global generation
423     init_Cluster()
424     while generation<LASTG:
425         if signal!=-1:
426             break
427         else:
428             print("代數= "+str(generation))
429             count_collidecount()
430             print("-------------output------------values--------------------------")
431             output()
432             print("------------- outputarray--------------------------------------")
433             outputarray()
434             mating()
435             print("------------- outputarray--------------------------------------")
436             outputarray()
437             print("-----------------mating選擇交叉---------outputnarray---------------")
438             outputnarray()
439             mutation()
440             print("-----------------mutation變異---------outputnarray---------------")
441             outputnarray()
442             print("------------- outputarray--------------------------------------")
443             outputarray()
444             copy_array()
445             # print("---------------------------------------------------------------")
446             # output_copy_array()
447             selection()
448             print("-----------------selection選擇下一代--------outputarray---------------")
449             outputarray()
450         generation+=1
451     print("signal = "+str(signal)+" max ="+str(max)+" max_generation = "+str(max_generation)) #max為最佳值, max_generation為產生最佳值的代數
452     print(max_array,end=" ")
453 
454 
455 if __name__ == "__main__":
456     main()