遗传算法(GA)

前言

遗传算法是典型的智能算法,其本质也是通过不断搜索从而得到最好的解决方案,但是与随机搜索不同,遗传算法的搜索具有一定的智能性,在搜索时它更倾向于选择适应度更优的解决方案,以下是遗传算法的一个基本流程图:
在这里插入图片描述
在上述基本遗传算法的基础上,可以在初始种群、个体选择、交叉方式、变异方式以及局部优化等方面作进一步调整,从而达到更好的效果。搜索类算法改进的本质基本都是让搜索具有全局性或者使得每次搜索的解更优质。

构造

使用遗传算法求解旅行商问题最主要的问题是编码和交叉,要保证交叉过程中尽量不产生坏解且交叉能够带来足够大的随机性,这具有一定的难度。
编码:[x1,x2…xn],xi代表第i个访问的城市,其中x1始终等于0
选择:使用轮盘赌策略选择两个交叉的个体
交叉:交叉最重要的是要保证交叉过后产生的个体为可行解。在进行交叉时,首先生成一个长度为n的0-1数组,然后根据数组中元素的值判断是否在此位置进行交叉,例如假设有4个城市,个体1为[0,1,2,3],个体2为[0,3,1,2],交叉数组为[0,0,1,0],这就代表只对第3个城市的位置进行交叉操作,交换两个个体第3个城市的位置,从而产生两个新为[0,1,3,2]和[0,3,2,1]。
局部优化:使用爬山法对每个个体进行优化。

代码

值得注意的点是,当子代发展到一定代数时,个体会趋向一致,这时候就会产生大量重复的个体,为了处理这种情况,对每一个重复的个体做一次随机扰动,保证每一代的个体中的没有重复个体。

import numpy as np
import pandas as pd
import random
import copy


# 计算距离
def calculate_distance(record):
    total_distance = 0
    if record[len(record) - 1]:
        record.append(0)
    for i in range(city_num):
        total_distance += distance[record[i]][record[i + 1]]
    return total_distance


# 交换位置
def swap(record, i, j):
    temp = record[i]
    record[i] = record[j]
    record[j] = temp


# 优化个体
def improve(record):
    for i in range(city_num):
        for j in range(city_num):
            if i == j:
                continue
            if record[i] * record[j] == 0:
                continue
            pre_distance = calculate_distance(record)
            swap(record, i, j)
            cur_distance = calculate_distance(record)
            if cur_distance > pre_distance:
                swap(record, i, j)
    return record


# 数据
distance = pd.read_table('distance.txt', header=None, index_col=None)
distance = distance.values.tolist()
city_num = len(distance)

# 参数
iter_num = 100  # 迭代次数
gen_num = 100  # 每代个体数
min_distance = 10000  # 最短距离
min_record = [-1 for i in range(city_num)]  # 最短距离对应遍历顺序
# 初始种群
records = [[i for i in range(city_num)] for j in range(gen_num)]
for i in range(gen_num):
    random.shuffle(records[i])
    for j in range(gen_num):
        if records[i][j] == 0:
            swap(records[i], j, 0)
            break
    if min_distance > calculate_distance(records[i]):
        min_distance = calculate_distance(records[i])
        min_record = copy.deepcopy(records[i])
# 遗传算法
for i in range(iter_num):
    new_records = []
    pro = []  # 选中每个个体的可能性
    sum_pro = 0  # 个体可能性之和
    for j in range(gen_num):
        pro.append(1 / calculate_distance(records[j]))
        sum_pro += pro[j]
    # 轮盘赌选择两个个体进行交叉
    for j in range(gen_num):
        idx = []  # 记录两个个体
        for k in range(2):
            rand_num = sum_pro * random.random()
            for jj in range(gen_num):
                if sum(pro[:jj + 1]) >= rand_num:
                    idx.append(jj)
                    break
        # 交叉择优得到一个新个体
        cross = [random.randint(0, 1) for ii in range(city_num)]  # 选择交叉位置,1交叉,0不交叉
        for jj in range(city_num):
            if not cross[jj]:
                continue
            swap_index = [0, 0]
            for k in range(city_num):
                if records[idx[0]][k] == jj:
                    swap_index[0] = k
                if records[idx[1]][k] == jj:
                    swap_index[1] = k
            swap(records[idx[0]], swap_index[0], swap_index[1])
            swap(records[idx[1]], swap_index[0], swap_index[1])
        if calculate_distance(records[idx[0]]) < calculate_distance(records[idx[1]]):
            new_records.append(records[idx[0]])
        else:
            new_records.append(records[idx[1]])
    records = copy.deepcopy(new_records)
    # 去重
    for j in range(gen_num):
        for jj in range(j + 1, gen_num):
            if records[jj] == records[j]:
                random.shuffle(records[jj])
                for jjj in range(1, len(records[jj])):
                    if records[jj][jjj] == 0:
                        if records[jj][0]:
                            swap(records[jj], 0, jjj)
                        else:
                            swap(records[jj], city_num, jjj)
    # 优化
    for j in range(gen_num):
        records[j] = copy.deepcopy(improve(records[j]))

    # 记录最优解
    for j in range(gen_num):
        if min_distance > calculate_distance(records[j]):
            min_distance = calculate_distance(records[j])
            min_record = copy.deepcopy(records[j])
            print(min_record, min_distance)

结果

每一代100个个体,经过100次迭代,找到了TSP问题的最优解,与贪心等启发算法相比,智能算法的全局性更强。另外,若是不加局部优化,那么求解效果会非常差,局部优化对于种群进化非常关键,如果不加局部优化那么每个个体的值都很差,子代的表现大概率也不会太好。

[0, 11, 21, 23, 22, 24, 17, 19, 18, 15, 12, 9, 8, 6, 7, 1, 2, 3, 5, 4, 10, 16, 25, 20, 13, 14, 0] 1390
[0, 14, 11, 12, 16, 21, 20, 7, 5, 3, 4, 6, 9, 13, 10, 8, 15, 18, 19, 17, 25, 23, 22, 24, 2, 1, 0] 1310
[0, 11, 21, 22, 23, 24, 25, 17, 18, 19, 16, 20, 15, 4, 5, 3, 2, 13, 10, 12, 14, 9, 8, 7, 6, 1, 0] 1239
[0, 14, 8, 15, 18, 17, 16, 9, 4, 5, 3, 6, 7, 19, 25, 22, 23, 24, 21, 20, 11, 10, 12, 13, 2, 1, 0] 1200
[0, 1, 6, 7, 15, 9, 10, 12, 14, 13, 2, 4, 3, 5, 8, 16, 20, 21, 24, 23, 22, 25, 17, 19, 18, 11, 0] 1192
[0, 1, 3, 5, 4, 2, 9, 16, 17, 19, 18, 15, 25, 22, 23, 24, 21, 20, 11, 12, 10, 8, 7, 6, 13, 14, 0] 1139
[0, 14, 2, 1, 3, 5, 4, 6, 7, 15, 18, 19, 17, 16, 20, 21, 25, 22, 23, 24, 11, 12, 10, 8, 9, 13, 0] 1018
[0, 14, 13, 9, 10, 12, 11, 20, 21, 24, 23, 22, 25, 17, 16, 19, 18, 15, 8, 7, 6, 4, 5, 3, 2, 1, 0] 983
[0, 24, 23, 22, 21, 25, 20, 16, 17, 19, 18, 15, 10, 12, 11, 14, 13, 9, 8, 7, 6, 4, 5, 3, 2, 1, 0] 940
[0, 24, 23, 22, 25, 21, 20, 16, 17, 19, 18, 15, 10, 12, 11, 14, 13, 9, 8, 7, 6, 4, 5, 3, 2, 1, 0] 937
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值