Solving the Eight Queens Problem with Genetic Algorithm

1. Problem description

The goal of the eight queens problem is to place 8 queens on a chess board such that no queen can attack any other queen. (The queen can attack any piece in the same row, column or diagonal)

2. Programming language and algorithm

Programming language:python

Algorithm: Genetic Algorithm

3. Solving ideas

1. Population initialization

First, the individual needs to be initialized, for the iiColumn i , coded as xxx , means theiixxof column irow x has a queen numbered from0 00 to start.

For an individual, you can use 8 88 codes to represent.

Example: The chessboard in the picture below can be coded 06471352 064713520 6 4 7 1 3 5 2 to represent:

At the time of initialization, the encoding is performed in a completely random manner, that is, the encoding set for each column is random,

# 生成一个体individual
for i in range(8):
    a = random.randint(0, 7)
    individual.append(a)

The initial population is set to 4 44 individuals, we generate4 44 individuals are added to the population to complete the initialization of the population.

# 计算生成的个体的适应度
fit_score = update_fitness_score(individual)
# 加入到种群中
parent_fitness.append(fit_score)
parent.append(individual)

2. Fitness function

The fitness function is expressed as: the number of queen pairs that do not attack each other

Then when the requirements of the topic are met, the 8 queens do not attack each other, a total of 8 × 7 / 2 = 28 8 × 7 / 2 = 288×7/2=2 8 pairs, that is, when the fitness is 28, the program can end.

So how to implement this program?

Select two columns (in order to avoid repeated operations, the number of the first column is artificially stipulated to be less than the number of the second column, if the two codes are not equal, it means that the two queens are not in the same row, and then we judge the absolute number of the two columns Whether the value is equal to the absolute value of the corresponding two codes, if not, it means that the two queens are not in the same column, then we put the fitness value + 1 +1+ 1 . In this way, the fitness function is designed.

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. How to select two male parents

According to the size of the probability, different ranges are delineated in an area according to the size of the fitness function. At this time, a random number is generated in the area. Whoever the random number falls in the range means who is selected. Repeat twice to select both parents.

4. How to select the hybrid point

Randomly select two points to form an interval, and exchange the genes of the two fathers in this interval

4. How to mutate

In nature, there is a certain probability of mutation. We assume that the probability in this question is 50 % 50\%5 0 % , generating a0 − 1 0-10Random floating point number between 1 , if the floating point number is greater than 0.5, mutate.

The form of variation is gene mutation, that is, the gene at a certain point randomly changes to 0 − 7 0-70One of 7 .

4. Program running results

Since the genetic algorithm simulates the behavior of genetic variation in natural selection, a number of logics that rely on probability are added to the algorithm. In the test, at least 1000 1000The result was obtained after more than 1000 iterations, and it took a maximum of more than 100,000 times to obtain the result. It is not ruled out that there will be hundreds of thousands or even millions of times before the result is obtained .

For this question, using the backtracking algorithm will be simpler and more efficient, but for some more complex problems, it is difficult to solve them through some fixed algorithms, then using the genetic algorithm can significantly reduce the complexity of the algorithm and make it easier to write code.

5. Code

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])

Guess you like

Origin blog.csdn.net/BWQ2019/article/details/118881748
Recommended