1、问题描述
八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上 放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n1×n1,而皇后个数也变成n2。而且仅当 n2 ≥ 1 或 n1 ≥ 4 时问题有解。
2、方法使用:之前都是图的盲目搜索来进行这个八皇后的问题,这次学习了了这个遗传算法,就用python实现了一下。
适应度函数的定义,种群大小、交叉比例、变异比例、算法终止条件 ;
(1)适应度函数= 28-互相攻击的皇后对的数目;
(2)种群大小设置为 20;
(3)交叉比例 1;
(4)变异比例 0.05;
(5)算法终止条件 当出现一个适应度为28的状态时停止算法或者迭代次数达到3000停止算法;
然后就开始我们的编码过程了,(这里这个可攻击的皇后对的计算函数也是用的之前的DFS解决八皇后的那个代码思路。)
import random
import copy
def Variataion(Population_list):#种群作为参数,进行变异 变异率为0.05
# print("准备开始变异",Population_list)
index1,index2=random.randint(0,19),random.randint(0,7)
# print(index1,index2)
value=random.randint(0,7)
Population_list[index1][index2]=value
return Population_list
def Crisscross(Population_list):#种群作为参数,进行交叉
# print(len(Population_list))
i=0
NewPopulation_list=[]
while True:
x=[]
y=[]
temp1=copy.deepcopy(Population_list[i])
temp2=copy.deepcopy(Population_list[i+1])
key=random.randint(0,7)
# print("测试点",key)
for j in range(key):
x.append(temp1[j])
for j in range(key,len(temp1)):
x.append(temp2[j])
for j in range(key):
y.append(temp2[j])
for j in range(key,len(temp1)):
y.append(temp1[j])
i+=2
# print(x,y)
NewPopulation_list.append(x)
NewPopulation_list.append(y)
if i==len(Population_list):
# print(NewPopulation_list)
return NewPopulation_list
def StartPopulation():#产生一个初始的随机种群,个体数量为20
Population_list=[]#种群列表
while True:
Individual_list=[]#个体列表
while True:
x=random.randint(0,7)
Individual_list.append(x)
if len(Individual_list)==8:
Population_list.append(Individual_list)
# print(Individual_list)
# print(Population_list)
break
if len(Population_list)==20:
#print(Population_list)
return Population_list
def tran(Individual):#将序列转化为矩阵
#print(Individual)
zt=[[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0]]
for i in range(8):
zt[Individual[i]][i]=8
#printf(zt)
return zt
pass
def Fitness(zt):#参数为矩阵
ans=0
for i in range(8):
for j in range(8):
if zt[i][j]==8:
for m in range(j):
if zt[i][m]==8:
ans+=1
for a in range(i):
for b in range(8):
if zt[a][b]==8:
if (a-b==i-j)or (a+b==i+j): # 判断对角线
ans+=1
return 28-ans
def printf(chess):#用来输出测试
for i in range(8):
for j in range(8):
print(chess[i][j],end=' ')
print()
def Iheritance():#遗传算法
Population_list=StartPopulation()
# print(Population_list)
# for item in Population_list:
# print(Fitness(tran(item)),end=' ')
# print()
index=0
while True:
if index>3000:
return -1
for item in Population_list:
if Fitness(tran(item))==28:
print("找到一个可行的解")
return item
select=[]#选择种群列表
for item in Population_list:
if Fitness(tran(item))>=20:
select.append(item)
if len(select)!=len(Population_list):
while True:
x=random.randint(0,19)
if Fitness(tran(Population_list[x]))>22:
select.append(Population_list[x])
if len(select)==len(Population_list):
break
# print(select)
Crisscross_list=Crisscross(select)#交叉遗传产生的种群
Variataion_list=Variataion(Crisscross_list)#变异之后产生的种群
Population_list.clear()
Population_list=copy.deepcopy(Variataion_list)
index+=1
if __name__=="__main__":
reslut=Iheritance()
if reslut==-1:
print("到达最大迭代次数")
else:
print(reslut)
printf(tran(reslut))
print("适应度为",Fitness(tran(reslut)))
pass