1. 問題の説明
8 クイーン問題の目的は、どのクイーンも他のクイーンを攻撃できないように、8 つのクイーンをチェス盤上に配置することです。(クイーンは同じ行、列、または対角線上にある任意のピースを攻撃できます)
2. プログラミング言語とアルゴリズム
プログラミング言語:python
アルゴリズム: 遺伝的アルゴリズム
3. アイデアの解決
1. 母集団の初期化
まず、 iiのために個人を初期化する必要があります。列i 、 xxxはiiを意味しますi列のxx行xには0 0から番号が付けられたクイーンがあります0で開始します。
個人の場合は、8 8を使用できます。表す8つのコード。
例: 下の図のチェス盤は、06471352 06471352とコード化できます。0 6 4 7 1 3 5 2を表すと次のようになります。
初期化時に、エンコードは完全にランダムな方法で実行されます。つまり、各列のエンコードセットはランダムです。
# 生成一个体individual
for i in range(8):
a = random.randint(0, 7)
individual.append(a)
初期母集団は4 4に設定されます。4人の個人から4 4を生成します4人の個人が母集団に追加され、母集団の初期化が完了します。
# 计算生成的个体的适应度
fit_score = update_fitness_score(individual)
# 加入到种群中
parent_fitness.append(fit_score)
parent.append(individual)
2.フィットネス機能
適応度関数は次のように表されます: 互いに攻撃しないクイーンペアの数
次に、トピックの要件が満たされると、8 人の女王は互いに攻撃しなくなり、合計8 × 7 / 2 = 28 8 × 7 / 2 = 288×7/2 _ _=2 8ペア、つまりフィットネスが 28 になると、プログラムを終了できます。
では、このプログラムをどのように実装すればよいのでしょうか?
2 つの列を選択します (操作の繰り返しを避けるために、最初の列の数は 2 番目の列の数よりも小さくなるように人為的に規定されています。2 つのコードが等しくない場合は、2 つのクイーンが同じではないことを意味します)値が対応する 2 つのコードの絶対値と等しいかどうかを判断します。そうでない場合は、2 つのクイーンが同じ列にないことを意味し、適合度の値を代入します。+1 +1+ 1。このようにしてフィットネス機能が設計される。
def update_fitness_score(individual):
value = 0
for i in range(8):
for j in range(i + 1, 8):
if individual[i] != individual[j]:
x = j - i
y = abs(individual[i] - individual[j])
if x != y:
value += 1
return value
3. 男親二人の選び方
確率の大小に応じて、適応度関数の大きさに応じて領域を分割し、その領域内で乱数を発生させ、その範囲に該当する乱数が誰を選択するかを意味します。2 回繰り返して両方の親を選択します。
4. ハイブリッドポイントの選定方法
ランダムに 2 点を選択して区間を形成し、この区間で 2 人の父親の遺伝子を交換します。
4. 突然変異のやり方
自然界には、一定の確率で突然変異が起こります。この質問の確率は50 % 50\%であると仮定します。5 0 %、0 − 1 0-10−1の間のランダムな浮動小数点数。浮動小数点数が 0.5 より大きい場合、変異します。
変化の形式は遺伝子の突然変異です。つまり、ある時点の遺伝子がランダムに0 − 7 0-7に変化します。0−7 つのうちの 1 つ
4. プログラム実行結果
遺伝的アルゴリズムは自然選択における遺伝的変動の挙動をシミュレートするため、確率に依存する多数のロジックがアルゴリズムに追加されます。テストでは、少なくとも1000 10001000回以上の反復を経て結果が得られ、結果が得られるまでに最大で10万回以上かかり、結果が得られるまでに数十万回、さらには数百万回かかる可能性も否定できません。
この質問では、バックトラッキング アルゴリズムを使用する方が簡単で効率的ですが、より複雑な問題の場合は、固定アルゴリズムでは解決することが困難です。その場合、遺伝的アルゴリズムを使用すると、アルゴリズムの複雑さが大幅に軽減され、簡単になります。コードを書くために。
5. コード
import copy
import random
import math
# 种群大小
population_size = 8
# 父种群的编码列表
parent = []
# 子种群的编码列表
children = []
# 父种群每个个体的适应度
parent_fitness = []
# 子种群每个个体的适应度
children_fitness = []
# 初始化个体
def initial_individual():
# 个体的编码
individual = []
# 8个编码
for i in range(8):
a = random.randint(0, 7)
individual.append(a)
# 计算生成的个体的适应度
fit_score = update_fitness_score(individual)
# 加入到种群中
parent_fitness.append(fit_score)
parent.append(individual)
return
# 更新适应度函数
def update_fitness_score(individual):
value = 0
for i in range(8):
for j in range(i + 1, 8):
if individual[i] != individual[j]:
x = j - i
y = abs(individual[i] - individual[j])
if x != y:
value += 1
return value
# 初始化1个种群,种群大小为population_size
def initial_population():
for i in range(population_size):
initial_individual()
return
# 选择出一个父本
def select():
# 所有个体的适应度之和
total_score = 0
for fit in parent_fitness:
total_score += fit
# 轮盘赌中的数
num = random.randint(0, total_score)
# 前面的适应度之和
front_score = 0
for i in range(population_size):
front_score += parent_fitness[i]
# 如果此时前面的适应度之和大于生成的随机数,那么该数必定落在编号为 i 的个体上
if front_score >= num:
return i
# 变异
def mutation(change_individual):
# 第pos个基因发生变异
pos = random.randint(0, 7)
# 改变的值
change = random.randint(0, 7)
change_individual[pos] = change
return change_individual
# 交叉产生后代
def hybridization():
# 选择两个父本
first = select()
second = select()
selected_parents = copy.deepcopy([parent[first], parent[second]])
# 交换从pos1到pos2的基因
pos1 = random.randint(0, 6)
pos2 = random.randint(0, 6)
# 保证pos1 <= pos2
if pos1 > pos2:
pos1, pos2 = pos2, pos1
# 交叉
tmp = selected_parents[0][pos1:pos2]
selected_parents[0][pos1:pos2] = selected_parents[1][pos1:pos2]
selected_parents[1][pos1:pos2] = tmp
# 一定的概率发生变异,假设概率为0.5
may = random.random()
if may > 0.5:
selected_parents[0] = mutation(selected_parents[0])
may = random.random()
if may > 0.5:
selected_parents[1] = mutation(selected_parents[1])
# 更新适应度
first_fit = update_fitness_score(selected_parents[0])
second_fit = update_fitness_score(selected_parents[1])
# 加入到子代中
children.append(selected_parents[0])
children.append(selected_parents[1])
children_fitness.append(first_fit)
children_fitness.append(second_fit)
return
# 初始化种群
initial_population()
# 计算迭代次数
count = 0
# not a number
find = float('nan')
while True:
count += 1
if count % 1000 == 0:
print('第%d' % count + '次迭代')
# 杂交population_size/2次产生population_size个后代
for k in range(population_size // 2):
hybridization()
# 如果某个个体适应度达到28,说明此时找到了一个解
for k in range(population_size):
if children_fitness[k] == 28:
# 记录解的位置
find = k
break
if not math.isnan(find):
break
# 将子代种群放入父代中作为新的父代,子代清空
parent[0:population_size] = children[0:population_size]
parent_fitness[0:population_size] = children_fitness[0:population_size]
children = []
children_fitness = []
# 此时找到满足要求的子代个体
res = children[find]
print(res)
# 构造棋盘
res_queen = [[0 for i in range(8)] for j in range(8)]
for t in range(8):
res_queen[res[t]][t] = 1
# 将棋盘打印
print("找到结果:")
for t in range(8):
print(res_queen[t])