用遗传算法解决八皇后问题

八皇后问题

八皇后问题是一个经典的计算问题,目标是在一个8x8的棋盘上放置8个皇后,使得它们互相之间不能攻击到对方。这个问题具有较高的复杂度,传统的穷举搜索方法效率低下。
问题建模
将每个皇后的位置编码为一个8位的数字串,其中每个位置代表皇后在对应列的行号。例如,6 2 3 0 7 2 5 0表示第1列的第6行放置了一个皇后。遗传算法的目标是找到一个合适的数字串,使得所有的皇后位置都满足不互相攻击的条件。

遗传算法设计

(1)初始化种群:随机生成一组初始个体,每个个体代表一个皇后的位置。
(2)适应度评估:根据每个个体的皇后位置计算适应度,适应度函数可以定义为冲突对数的倒数,即越小越好。具体而言,我们遍历每对皇后,并检查它们是否在同一行、同一列或同一对角线上。如果两个皇后之间存在冲突,则冲突计数加1。最终,适应度的值被定义为冲突数的倒数加1,这样可以使适应度越高的个体具有更好的解。
例如,如果一个个体的八皇后方案中没有任何冲突,则适应度为1。如果有一个冲突,适应度为1/2。如果有两个冲突,适应度为1/3,以此类推。
(3)选择:使用轮盘赌选择方法,按照个体适应度比例选择父代个体。
(4)交叉:采用单点交叉操作,将选出的父代个体进行染色体交换,生成新的后代个体。
(5)突变:对新生个体进行随机变异操作,引入新的遗传信息。
(6)迭代优化:重复进行选择、交叉和突变等操作,直到满足停止条件(如达到最大迭代次数或找到最优解)。

以下给出了两个版本的求解代码

1.用遗传算法求解一个正确的解,通过迭代找到最终的结果

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

运行结果,每次运行的迭代次可能不同:

第1000次迭代
第2000次迭代
第3000次迭代
第4000次迭代
第5000次迭代
第6000次迭代
第7000次迭代
第8000次迭代
第9000次迭代
第10000次迭代
第11000次迭代
第12000次迭代
第13000次迭代
第14000次迭代
第15000次迭代
第16000次迭代
第17000次迭代
第18000次迭代
第19000次迭代
第20000次迭代
第21000次迭代
第22000次迭代
第23000次迭代
第24000次迭代
第25000次迭代
第26000次迭代
第27000次迭代
第28000次迭代
第29000次迭代
第30000次迭代
第31000次迭代
第32000次迭代
第33000次迭代
[4, 7, 3, 0, 2, 5, 1, 6]
找到结果:
[0, 0, 0, 1, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 1, 0]
[0, 0, 0, 0, 1, 0, 0, 0]
[0, 0, 1, 0, 0, 0, 0, 0]
[1, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 1]
[0, 1, 0, 0, 0, 0, 0, 0]

2.第二版本,该代码中对各参数设置不同的值进行了比较,并进行绘图

import random
import numpy as np
import matplotlib.pyplot as plt

# 定义棋盘大小
BOARD_SIZE = 8


def initial_population(population_size):
    population = []
    for _ in range(population_size):
        individual = [random.randint(0, BOARD_SIZE - 1) for _ in range(BOARD_SIZE)]
        population.append(individual)
    return population


def calculate_fitness(individual):
    conflicts = 0
    for i in range(BOARD_SIZE):
        for j in range(i + 1, BOARD_SIZE):
            if individual[i] == individual[j]:
                conflicts += 1
            offset = j - i
            if individual[i] == individual[j] + offset or individual[i] == individual[j] - offset:
                conflicts += 1
    return 1 / (conflicts + 1)


def selection(population, fitness_values):
    total_fitness = sum(fitness_values)
    probabilities = [fitness / total_fitness for fitness in fitness_values]
    selected_indices = random.choices(range(len(population)), probabilities, k=2)
    return [population[idx] for idx in selected_indices]


def crossover(parent1, parent2, crossover_rate):
    if random.random() > crossover_rate:
        return parent1, parent2
    crossover_point = random.randint(1, BOARD_SIZE - 1)
    child1 = parent1[:crossover_point] + parent2[crossover_point:]
    child2 = parent2[:crossover_point] + parent1[crossover_point:]
    return child1, child2


def mutation(individual, mutation_rate):
    mutated_individual = individual.copy()
    if random.random() < mutation_rate:
        gene_index = random.randint(0, BOARD_SIZE - 1)
        new_gene = random.randint(0, BOARD_SIZE - 1)
        mutated_individual[gene_index] = new_gene
    return mutated_individual


def genetic_algorithm(population_size, max_iterations, crossover_rate, mutation_rate):
    population = initial_population(population_size)
    best_fitness_values = []

    for _ in range(max_iterations):
        fitness_values = [calculate_fitness(individual) for individual in population]
        best_fitness = max(fitness_values)
        best_fitness_values.append(best_fitness)

        if best_fitness == 1:
            break

        new_population = []
        for _ in range(population_size // 2):
            parent1, parent2 = selection(population, fitness_values)
            child1, child2 = crossover(parent1, parent2, crossover_rate)
            new_population.append(child1)
            new_population.append(child2)

        mutated_population = [mutation(individual, mutation_rate) for individual in new_population]
        population = mutated_population

    best_individual = population[fitness_values.index(max(fitness_values))]
    return best_individual, best_fitness_values


# 设置参数
population_size = 100
max_iterations = 1000
crossover_rates = [0.6, 0.7, 0.8, 0.9]
mutation_rates = [0.05, 0.1, 0.15, 0.2]
flag = True
flag1 = True


def result1():
    # 运行遗传算法并记录结果
    results1 = []
    for cr in crossover_rates:
        for mr in mutation_rates:
            best_solution, best_fitness_values = genetic_algorithm(population_size, max_iterations, cr, mr)
            results1.append((cr, mr, best_solution, best_fitness_values))
    # 绘制图表
    plt.figure(figsize=(12, 8))
    for i, result in enumerate(results1):
        cr, mr, best_solution, best_fitness_values = result
        print(cr,mr,best_solution)
        label = f"crossover rate: {cr}, mutation rate: {mr}"
        plt.plot(best_fitness_values, label=label)
    plt.xlabel("Iterations")
    plt.ylabel("Fitness")
    plt.legend()
    plt.title("Genetic Algorithm Performance")
    plt.show()


def result2():
    results2 = []
    for population_size in population_sizes:
        best_solution, best_fitness_values = genetic_algorithm(population_size, max_iterations, crossover_rate,
                                                               mutation_rate)
        results2.append((population_size, best_solution, best_fitness_values))
        
    # 绘制图表
    plt.figure(figsize=(12, 8))
    for i, result in enumerate(results2):
        population_size, best_solution, best_fitness_values = result
        print(population_size,best_solution)
        label = f"Population size: {population_size}"
        plt.plot(best_fitness_values, label=label)
    plt.xlabel("Iterations")
    plt.ylabel("Fitness")
    plt.legend()
    plt.title("Genetic Algorithm Performance with Different Population Sizes")
    plt.show()


while flag1 == True:
    if flag == True:
        result1()
        flag = False
    else:
        # 设置参数
        max_iterations = 1000
        crossover_rate = 0.7
        mutation_rate = 0.1

        # 不同的种群规模数
        population_sizes = [50, 100, 200, 300, 400]
        result2()
        flag1 = False

运行结果:

0.6 0.05 [0, 6, 4, 7, 1, 3, 5, 2]
0.6 0.1 [1, 7, 2, 0, 6, 4, 1, 5]
0.6 0.15 [2, 6, 1, 7, 5, 3, 0, 4]
0.6 0.2 [5, 2, 0, 7, 4, 1, 3, 6]
0.7 0.05 [2, 6, 3, 7, 0, 4, 5, 1]
0.7 0.1 [2, 6, 1, 7, 5, 3, 0, 4]
0.7 0.15 [4, 7, 3, 0, 6, 1, 5, 2]
0.7 0.2 [6, 1, 3, 0, 7, 4, 2, 5]
0.8 0.05 [4, 1, 5, 6, 2, 0, 7, 3]
0.8 0.1 [6, 4, 2, 0, 5, 7, 1, 3]
0.8 0.15 [3, 6, 0, 7, 4, 1, 5, 2]
0.8 0.2 [4, 0, 0, 5, 3, 1, 6, 2]
0.9 0.05 [0, 3, 5, 2, 6, 1, 7, 4]
0.9 0.1 [4, 2, 7, 3, 6, 0, 5, 1]
0.9 0.15 [5, 1, 6, 4, 2, 7, 5, 3]
0.9 0.2 [1, 5, 0, 6, 3, 7, 2, 4]

在这里插入图片描述

50 [5, 5, 1, 6, 4, 2, 7, 3]
100 [6, 3, 1, 7, 5, 0, 2, 4]
200 [5, 3, 1, 7, 4, 6, 0, 2]
300 [4, 6, 0, 2, 7, 5, 3, 1]
400 [4, 1, 5, 0, 6, 3, 7, 2]

在这里插入图片描述

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值