遗传算法实现n皇后问题

内容:

用遗传算法求解n皇后问题。n*n的棋盘上摆放n个皇后,两个皇后如果在同一直线或者同一对角线就会互相攻击。 找一种摆法,使得任意两个皇后之间都不会互相攻击。

问题描述:

遗传算法举例:8皇后问题

个体:长为8的序列,每一列的值代表对 应列的皇后所在的行。 下图状态:83742516 在这里插入图片描述

  1. 适应度函数= 28-互相攻击的皇后对 的数目 (不互相攻击的皇后对的数目)
  2. 好的状态对应较大的适应度函数值 (min = 0, max = 8 × 7/2 = 28。
    在这里插入图片描述

注意事项:

  1. 种群大小(每代的个体数量)设置:可尝试20,50,100。
  2. 迭代终止条件:对于八皇后问题,适应度函数达到28(找到最优解)就可 以终止。也有可能你的算法写的有问题,导致适应度函数值永远无法到达 28,所以最好还是设一个最大迭代步数,或者当适应度函数值不发生变化 时终止迭代。
  3. 交叉率:0.5~1,不能太小 。
  4. 变异率:0.01~0.2,只允许少数个体变异,不能太大。
  5. 每一代最好将上一代中适应度函数值高的一些个体保留到下一代,这样就 确保下一代的结果不会比上一代差。
  6. 最后的结果画个简单的8皇后摆放的图。这样才能看出是否有冲突。相当 于显示一个8*8的矩阵,例如有皇后的地方显示数字8,其他地方显示数字 0。
  7. 如果能解决8皇后问题,也可以尝试N皇后问题(例如N=32)。

流程图如下:
在这里插入图片描述

 import copy
import numpy as np

path = '八皇后种群.txt'
f=open(path, 'w',encoding='UTF-8')
f.write('初始化种群为:\n')

每个个体不互相攻击的皇后对的数目 列上不可能有冲突

def unfighting(sort):
    alist = list(set(sort))
    num = 0  # 初始化皇后冲突的对数为0
    # num=len(sort)-len(alist)   #求行上面冲突的的皇后个数

    # 求行上面冲突的的皇后对数
    x = []
    sort = list(sort)
    for i in range(len(alist)):
        x.append(sort.count(alist[i]))
    for i in x:
        if i >= 2:
            num = num + i * (i - 1) // 2
    # 求斜线上冲突的皇后的对数
    for i in range(n - 1):
        for j in range(i+1, n):
            if sort[i] - sort[j] == i - j or sort[i] - sort[j] == j-i :
                num = num + 1

    return int(n*(n-1)/2) - num

绘制棋盘并打印

def drawchess(sort):

    chess = np.zeros((len(sort), len(sort)), dtype=int)
    # 创建八皇后棋盘
    for i in range(len(sort)):
        chess[sort[i]][i] = len(sort)
    for i in range(n):
        for j in range(n):
            if chess[i][j]==0:
                print('O',end='\t')
            else:
                print(chess[i][j],end='\t')
        print()

适应度函数

def FitFunction(sorts):
    # fits=np.zeros((len(sorts)),dtype=int)  #每个个体适应度初始化为0
    fits = []
    for sort in sorts:
        fits.append(unfighting(sort))

    if int(n*(n-1)//2) in fits:
        return fits
    sum = np.sum(fits)
    for i in range(len(sorts)):
        fits[i] = fits[i] / sum
    return fits

淘汰函数

def discard(sorts):
    deepth.append(0)

    if len(deepth)==2800:
        print('超过了最大深度')
        return
    fits = FitFunction(sorts)
    f.write('第' + str(len(deepth)) + '代' + '\n')
    f.write(str(fits) + '\n')
    #如果不打架的皇后个数为28则画出相应的棋盘
    if int(n*(n-1)//2) in fits:
        for y in fits:
            if y == int(n*(n-1)//2):
                print("优秀个体为:")
                print(sorts[fits.index(n*(n-1)//2)])
                print("棋盘为:")
                drawchess(sorts[fits.index(n*(n-1)//2)])

        return sorts

    new_sorts = []
    # 适应度低的终将被淘汰 在0.13~0.145之间随机产生一个数,适应度小于该数的会被淘汰
    miss = np.random.uniform(0.0130, 0.0145)
    for i in range(len(sorts)):
        if fits[i] > miss:
            new_sorts.append(sorts[i])

    # 保证新种群的个体数和旧种群数相同
    sub = len(sorts) - len(new_sorts)
    if sub > 0:
        if sub> int(np.ceil(len(sorts) * 0.3)):
            new_sorts.clear()
            # 将适应度低的个体淘汰掉 比例为25%
            for i in range(len(sorts)):
                sorts[i].append(fits[i])  # 将其对应的适应度以以匹配起来
            sorts.sort(key=lambda x: x[n], reverse=False)  # 按照适应度的高低排序:低到高
            indexstart = int(np.ceil(sub * 0.25))
            new_sorts=sorts[indexstart:]

        sub = len(sorts) - len(new_sorts)
        s = np.random.randint(0, len(new_sorts), sub)  #随机选择sub个位置上的个体数增加
        for x in s:
            new_sorts.insert(len(new_sorts)+1, new_sorts[x])

    np.random.shuffle(new_sorts)  # 随机打乱顺序
    Selection(new_sorts)

交叉变异函数

# 选择交叉变异函数  两两组合 用随机数产生交叉的位置
def Selection(sorts):
    fits = FitFunction(sorts)
    Len = len(sorts)
    new_sorts = copy.deepcopy(sorts)
    # 将适应度高的个体保留以保证子代的结果不会比父代差 比例为5%
    for i in range(Len):
        new_sorts[i].append(fits[i])  # 将其对应的适应度以以匹配起来
    new_sorts.sort(key=lambda x: x[8], reverse=True)  # 按照适应度的高低排序
    indexstart = int(np.ceil(Len * 0.05))
    del new_sorts[indexstart:]

    # 将保留的高适应度的个体从要进行交叉互换的队列里面删除
    for x in new_sorts:
        del x[8:]
        sorts.remove(x)

    # 交叉互换
    corssindex = np.random.randint(0, n, size=len(sorts) // 2)  # 随机产生每对交叉互换的位置
    for i in range(len(sorts) // 2):
        new1 = []
        new2 = []
        for x in sorts[2 * i][:corssindex[i]] :
            new1.append(x )
        for x in sorts[2 * i + 1][corssindex[i]:]:
            new1.append(x )
        for x in sorts[2 * i + 1][:corssindex[i]]:
            new2.append(x)
        for x in sorts[2 * i][corssindex[i]:]:
            new2.append(x)
        new_sorts.append(new1)
        new_sorts.append(new2)
    if len(sorts) % 2 == 1:  # 个体数为奇数个,将父代最后一个保留到子代中
        new_sorts.append(sorts[len(sorts) - 1])

    # 变异
    Mutation = np.random.uniform(0.001, 0.04)  # 在0.01~0.2之间随机产生一个数作为变异率
    Mutation_num = int(np.floor(Mutation * Len))  # 变异的数目
    Mutations = np.random.randint(0, len(new_sorts), Mutation_num)  # 随机产生变异的个体编号
    Mutationindex = np.random.randint(0, n, Mutation_num)  # 随机产生变异的个体的变异位置
    s = np.random.randint(0, n, Mutation_num)  # 随机产生突变成的数字
    for i in range(Mutation_num):
        new_sorts[Mutations[i]][Mutationindex[i]] = s[i]
    discard(new_sorts)

主函数

def main():
    global n
    global deepth
    deepth=[]
    n = eval(input('请输入皇后个数:'))

    sorts = []
    sorts_size = (np.random.randint(7 * n, 13 * n, size=1))  # 初始化种群的大小
    for i in range(sorts_size[0]):
        sort = np.random.randint(0, n, size=n)
        sorts.append(list(sort))
    for i in range(sorts_size[0]):
        f.write(str(sorts[i]) + '\n')

    sorts=discard(sorts)

    #print(sorts)
    f.write("最后的种群为:" + '\n')
    for i in range(sorts_size[0]):
        f.write(str(sorts[i]) + '\n')
    f.close()

if __name__ == '__main__':
    main()

结果就在下面啦:

在这里插入图片描述在这里插入图片描述

  • 3
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是遗传算法实现八皇后问题的Python代码: ```python import random # 棋盘大小 BOARD_SIZE = 8 # 种群大小 POPULATION_SIZE = 100 # 繁殖代数 GENERATIONS = 1000 # 交叉概率 CROSSOVER_RATE = 0.8 # 变异概率 MUTATION_RATE = 0.2 # 定义一个个体类 class Individual: def __init__(self, chromosome): self.chromosome = chromosome self.fitness = self.calculate_fitness() # 计算个体适应度 def calculate_fitness(self): clashes = 0 for i in range(len(self.chromosome)): for j in range(i + 1, len(self.chromosome)): if abs(self.chromosome[i] - self.chromosome[j]) == j - i: clashes += 1 return 1 / (clashes + 1) # 初始化种群 def init_population(): population = [] for i in range(POPULATION_SIZE): chromosome = random.sample(range(BOARD_SIZE), BOARD_SIZE) population.append(Individual(chromosome)) return population # 遗传算法 def genetic_algorithm(): # 初始化种群 population = init_population() # 进化 for generation in range(GENERATIONS): # 对种群进行排序 population = sorted(population, key=lambda x: x.fitness, reverse=True) # 输出最优解 print("Generation:", generation, "Best fitness:", population[0].fitness) # 如果找到最优解,则退出循环 if population[0].fitness == 1: break # 选择 selected_parents = selection(population) # 交叉 offspring_crossover = crossover(selected_parents) # 变异 offspring_mutation = mutation(offspring_crossover) # 更新种群 population = selected_parents + offspring_mutation # 对最终种群进行排序 population = sorted(population, key=lambda x: x.fitness, reverse=True) # 输出最优解 print("Generation:", generation + 1, "Best fitness:", population[0].fitness) print("Solution:", population[0].chromosome) # 选择 def selection(population): selected_parents = [] # 选择最优的前N个个体作为父母 for i in range(int(POPULATION_SIZE / 2)): # 选择两个随机个体 parents = random.sample(population[:int(POPULATION_SIZE / 2)], 2) # 选择适应度更高的个体作为父母 selected_parents.append(max(parents, key=lambda x: x.fitness)) return selected_parents # 交叉 def crossover(selected_parents): offspring_crossover = [] for i in range(int(POPULATION_SIZE / 2)): # 如果随机数小于交叉概率,则进行交叉 if random.random() < CROSSOVER_RATE: # 随机选择两个父母 parents = random.sample(selected_parents, 2) # 随机选择交叉点 crossover_point = random.randint(1, BOARD_SIZE - 2) # 交叉生成两个后代 offspring1 = parents[0].chromosome[:crossover_point] + parents[1].chromosome[crossover_point:] offspring2 = parents[1].chromosome[:crossover_point] + parents[0].chromosome[crossover_point:] # 将后代加入到新种群中 offspring_crossover.append(Individual(offspring1)) offspring_crossover.append(Individual(offspring2)) else: # 如果随机数大于交叉概率,则直接将父母加入到新种群中 offspring_crossover.append(selected_parents[i]) offspring_crossover.append(selected_parents[i + 1]) return offspring_crossover # 变异 def mutation(offspring_crossover): offspring_mutation = [] for i in range(len(offspring_crossover)): # 如果随机数小于变异概率,则进行变异 if random.random() < MUTATION_RATE: # 随机选择一个基因进行变异 mutation_point = random.randint(0, BOARD_SIZE - 1) # 随机生成一个新的基因 mutation_gene = random.randint(0, BOARD_SIZE - 1) # 将基因替换为新的基因 offspring_crossover[i].chromosome[mutation_point] = mutation_gene offspring_mutation.append(offspring_crossover[i]) return offspring_mutation # 运行遗传算法 genetic_algorithm() ``` 该程序使用遗传算法解决八皇后问题。其中,个体适应度的计算方式为:将所有冲突的皇后对数加1,然后取其倒数作为适应度。种群初始化时,每个个体的染色体都是一个随机排列的数列,表示每个皇后所在的列数。在每一代的进化过程中,先对种群进行排序,然后选择适应度更高的个体作为父母进行繁殖。选择时,每次随机选择两个个体,然后选择其中适应度更高的个体作为父母。交叉时,每次随机选择两个父母,然后随机选择一个交叉点,将交叉点之前的基因从一个父母继承,交叉点之后的基因从另一个父母继承,生成两个后代。变异时,每次随机选择一个个体,然后随机选择一个基因进行变异,将其替换为一个随机生成的新基因。最后,输出最优解并结束程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值