遗传算法详解与改良遗传算法

1.遗传算法简介

遗传算法(GA)是用于解决NP难问题如JSP问题,TSP问题常用的启发式算法。上世纪70年代由美国的John holland提出,是运用计算机仿真,通过交叉变异等方式,模拟自然进化过程搜索最优解的方法。主要特点是对非线性极值问题能以概率 1 跳出局部最优解,找到全局最优解。

2.初始种群的选择

在求解取值连续的问题时可使用完全随机的值,但在求解旅行商问题等非连续的问题时通常采用改良圈法,得到一个相对较优的解,然后再利用遗传算法得出最优解。

改良圈法基本原理

对于随机产生的某条路线
C i j = w 1 w 2 w 3 . . . w u − 1 w u w u + 1 . . . w v − 1 w v w v + 1 . C_{ij} = w_{1}w_{2}w_{3}...w_{u-1}w_{u}w_{u+1}...w_{v-1}w_{v}w_{v+1}. Cij=w1w2w3...wu1wuwu+1...wv1wvwv+1.
如果满足
d ( w u , w v − 1 ) + d ( w u + 1 , w v ) < d ( w u , w u + 1 ) + d ( w v , w v − 1 ) d(w_{u},w_{v-1})+d(w_{u+1},w_{v})<d(w_{u},w_{u+1})+d(w_{v},w_{v-1}) d(wu,wv1)+d(wu+1,wv)<d(wu,wu+1)+d(wv,wv1)
其中d(x,y)为x,y两点的间距
原路线修改为
C i j = w 1 w 2 w 3 . . . w u − 1 w u w v − 1 w v − 2 . . . w u + 1 w v w v + 1 . C_{ij} = w_{1}w_{2}w_{3}...w_{u-1}w_{u}w_{v-1}w_{v-2}...w_{u+1}w_{v}w_{v+1}. Cij=w1w2w3...wu1wuwv1wv2...wu+1wvwv+1.
即u,v之间所有点的顺序反转

改良圈法代码实现

这部分的代码以华为面试的蜜蜂采蜜问题为例
即输入A,B,C,D,E五个点的相对于原点的坐标,得出从原点出发经过这五个点后返回原点的最小路径
测试用例:
输入:200,0,200,10,200,50,200,30,200,25
输出:456

import numpy as np
import math
x=[0]
y=[0]
final_list=[]
#计算路径的长度
def cul_dist(org_rout):
    sum=0
    for i in range(len(org_rout)-1):
        sum+=d[org_rout[i]][org_rout[i+1]]
    return sum
#输入坐标
for i in range(5):
    temp_x=int(input("请输入x坐标"))
    temp_y=int(input("请输入y坐标"))
    x.append(temp_x)
    y.append(temp_y)
#初始化并得到距离矩阵
d=np.zeros((6,6))
for i in range(6):
    for j in range(6):
        d[i][j]=math.sqrt((x[i]-x[j])**2+(y[i]-y[j])**2)
#容易陷入局部最优,多次运行确保得到最小值
for i in range(20):
    #随机生成的路线
    org_rout=np.random.choice(range(1,6),size=5,replace=False)
    #这里是改良圈法的开始
    for m in range(6):
        #退出条件
        flag=0
        for j in range(3):
            for k in range(j+2,5):
                #进行判断
                if d[org_rout[j]][org_rout[k-1]]+d[org_rout[j+1]][org_rout[k]]<d[org_rout[j]][org_rout[j+1]]+d[org_rout[k-1]][org_rout[k]]:
                    org_rout[j+1:k]=org_rout[k-1:j:-1]
                    flag=1
        #退出
        if flag==0:
            break
    #补上起点终点,便于计算长度
    org_rout=np.insert(org_rout,0,0)
    org_rout=np.append(org_rout,0)
    final_list.append(cul_dist(org_rout))
#得到最小值
print(np.array(final_list).min())

得到结果为456.155,与题目答案一致
PS:这并不是最优的解法,只是恰好可以使用改良圈法
容易发现改良圈法通常只是得到局部最优解,也就引出了我们今天的主题“遗传算法”,将其作为遗传算法的初始种群,可以大大减少遗传代数

3.遗传算法

包括前面提到的种群选择,还有建立目标函数,交叉,变异,计算适应度以及选择等几大操作,接下来我以一道相对复杂的TSP问题为例,介绍遗传算法的使用

问题简介

A市某辆大货车要前往三十个点中确定的十四个点送货,已知其可从任意一点出发出发和各点的位置坐标,求一条最短的路线,使大货车送完之后仍然回到出发点

编码与解码

离散点的问题可采用一串随机数作为编码,解码的方式为随机数从小到大排列的下标,例如对于五个点的问题,有编码[0.22,0.98,0.34,0.42,0.17],对应路径5-1-3-4-2

对于连续取值的问题,可使用二进制编码
二进制的编码和解码可以参考其他的文章
遗传算法详解 附python代码实现

构造目标函数

通常由个体解码后对应值计算得到,本题中为路径的长度

进行单点交叉

由父本和母本两个个体繁殖产生新的个体的过程被称为交叉,子代获取了部分父本和部分母本的DNA,这个过程中子代继承了上一代的优良特性,在不断的交叉和变异中,最终得到问题的最优解
通常选取交叉率为0.8~1之间
具体的操作为,随机选取一个交叉点,一个子代得到交叉点之前父本的基因和交叉点之后母本的基因,另一个子代得到交叉点之前母本的基因和交叉点之后父本的基因
例如选取父本[0.22,0.98,0.34,0.42,0.17]
母本[0.55,0.32,0.76,0.23,0.01]
选取第二个点之后为交叉点
得到子代分别为[0.22,0.98,0.76,0.23,0.01]和[0.55,0.32,0.34,0.42,0.17]
最后将子代加入群体

随机进行变异

从序列中随机选取三个位置u<v<w,位于u,v之间的部分移出并插入w之后
这是实现种群多样性的手段,也是实现全局最优的保证

计算个体在环境的适应度

为个体在环境中的适应程度,适应度越高代表个体越适合于这个环境,被选择的几率也就越大
本题中解码出路径越短适应性也就越强,我采用了种群解码的最大值减去个体解码的值作为该个体的适应度

选择个体

为了体现出达尔文“物竞天择,适者生存”的自然选择法则,我们应该尽可能选择适应度更高的个体,淘汰掉不适合环境的个体

选择新的种群时可以进行概率选择,也可以直接选择适应度最高的那一部分个体

总的代码如下:

import numpy as np
import pandas as pd
import math

pop_size=1000
cross_rate=0.95
heter_rate=0.1
generation=50

data=pd.read_csv("经纬坐标.csv")
distance_arr=np.zeros([30,30])
#城市中道路往往呈网格状,利用坐标差绝对值得到距离矩阵
for i in range(30):
    for j in range(30):
        distance_arr[i][j]=abs(data.values[i,1]-data.values[j,1])+abs(data.values[i,2]-data.values[j,2]) 
area=[6,7,8,9,10,21,22,23,24,25,26,27,28,30]
pop_total=[]
#解码,根据随机数列表返回对应路径
def intep(rand_rout):
    rand_arg=np.argsort(rand_rout)
    point_choiced=[]
    for k in rand_arg:
        point_choiced.append(area[k])
    return point_choiced
#根据路径计算对应长度
def culc(pop_total):
    dist_list=[]
    for pot in pop_total:
        rout=intep(pot)
        dist=distance_arr[rout[len(rout)-1]-1][rout[0]-1]
        for i in range(len(rout)-1):
            dist+=distance_arr[rout[i]-1][rout[i+1]-1]
        dist_list.append(dist)
    dist_list=np.array(dist_list)
    return (dist_list.max()-dist_list)+1e-4
#交叉操作
def cross(pop_total):
    new_pop_total=pop_total.copy()
    for father in pop_total: 
        if np.random.rand() < cross_rate:
            #子代c1,c2
            c1=[]
            c2=[]
            choc=math.floor(np.random.rand()*len(pop_total))
            mother=pop_total[choc]
            cross_p=np.random.randint(low=0, high=14)
            c1=father
            c1[cross_p:]=mother[cross_p:]
            new_pop_total=np.vstack((new_pop_total,c1))
            c2=mother
            c2[cross_p:]=father[cross_p:]
            #插入种群中
            new_pop_total=np.vstack((new_pop_total,c2))
    return new_pop_total
#变异操作
def heter(pop_total):
    for i in pop_total: 
        if np.random.rand() < cross_rate:
            i_c=[]
            for ele in i:
                i_c.append(ele)
            #随机产生的三个位置
            rand_p=np.floor(np.random.rand(3)*14).astype(int)
            rand_p=np.sort(rand_p)
            temp=i_c[rand_p[0]:rand_p[1]]
            del i_c[rand_p[0]:rand_p[1]]
            i_c.insert(rand_p[2],temp)
            i=i_c
    return pop_total
#从种群中挑选下一代的个体
def select(pop_total, fitness): 
    index = np.argsort(-fitness)
    return np.array(pop_total)[index[:pop_size]]

#生成初始种群
for i in range(pop_size):
    rand_rout=np.random.rand(14)
    point_choiced=intep(rand_rout)
    #使用改良圈法
    for j in range(len(point_choiced)):
        flag=0
        for m in range(len(point_choiced)-2):
            for n in range(m+2,len(point_choiced)):
                if distance_arr[point_choiced[m]-1][point_choiced[n-1]-1]+distance_arr[point_choiced[m+1]-1][point_choiced[n]-1]<distance_arr[point_choiced[m]-1][point_choiced[m+1]-1]+distance_arr[point_choiced[n]-1][point_choiced[n-1]-1]:
                    rand_rout[m+1:n]=rand_rout[n-1:m:-1]
                    flag=1
        if flag==0:
            break
    pop_total.append(rand_rout)
pop_total=np.array(pop_total)

for i in range(generation):    
    pop_total=cross(pop_total)
    pop_total=heter(pop_total)
    fitness=culc(pop_total)
    pop_total=select(pop_total, fitness)
dist_list=[]
for pot in pop_total:
    rout=intep(pot)
    dist=distance_arr[rout[len(rout)-1]-1][rout[0]-1]
    for i in range(len(rout)-1):
        dist+=distance_arr[rout[i]-1][rout[i+1]-1]
    dist_list.append(dist)
print(np.array(dist_list).min())

用时约15s,得出结果为12.9128

4.改良遗传算法

a.在个体配对时讲究“门当户对”
b.使用正态分布选择变异点
c.优化适应度函数,提高选择更优解的比例
d.防止优良解因为变异遭到破坏,对于最优解进行保护
e.引入遗传-灾变算法,有效避免了局部最优解的垄断,增强了全局搜索的能力

  • 9
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
分排序):"); orderBy = scanner.nextInt(); printStudentList(orderBy); break; case 5: printLowScoreStudents(); break; case 6: printHighScoreStudents(); break; case 7: save遗传算法是一种模拟自然进化过程的优化算法,它通过模拟基因遗传ToFile("students.txt"); break; case 0: System.out.println("感谢使用学生管理系统!"); System、交叉和变异等自然现象,对问题进行搜索和优化,从而得到最优解或次.exit(0); default: System.out.println("无效的选择!"); } } } } ``` 7.优解。遗传算法通常由三个阶段组成:选择、交叉和变异。在选择阶段 用户验证 我们需要在程序启动时进行用户验证,只有输入正确的用户名和密码才能使用学生管理,通过适应度函数对种群中的个体进行评估,并保留一部分适应度较高的个系统。可以使用Java的控制台输入输出来实现。下面是一个简单的示例代码: ```java 体;在交叉阶段,对这些个体进行随机交叉,产生新的个体;在变异public class StudentManager { private Scanner scanner = new Scanner(System.in); // 控制台输入 // 启动学生管理阶段,则对新个体进行随机变异,以增加解空间的探索能力。通过多次迭系统 public void start() { System.out.println("请输入用户名:"); String username = scanner.next(); System.out.println("请输入密码:"); String password = scanner.next(); if (!username.equals("admin") || !password.equals("123456"))代,遗传算法能够不断优化解的质量,逐渐接近最优解。遗传算法 { System.out.println("用户名或密码错误,程序退出!"); System.exit(0); } loadFromFile("students.txt广泛应用于各种优化问题,例如函数优化、组合优化、机器学习等领域。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值