遗传算法求解TSP问题

流程图

在这里插入图片描述

数据集

att48.tsp

关键要素

  1. 解的编码:实数编码
  2. 群体初始化:随机最近邻居构造启发式算法生成一个初始满意解,其余随机生成
  3. 适应度评价函数:总距离的倒数
  4. 选择:依概率轮赌盘法选择父代
  5. 交叉:顺序交叉
  6. 变异:2-opt变异 (父代一定变异,子代依概率变异)
  7. 相关参数: N=100;Pm=0.02;Maxlter=2000
  8. 改进:在以上常规遗传算法的基础上,我又添加了局部搜索算法,以保持每代种群质量的优良性,提高对最优解的搜索能力,但降低了搜索的随机性。

代码

import random
import numpy as np
import math
import pandas as pd
import copy
import matplotlib.pyplot as plt
import time
import random

def data_deal(city):
    city = np.array(city[0][6:len(city) - 1])
    city_name = city.tolist()
    chu_li = []
    for i in range(0, len(city_name)):
        temp = city_name[i].split()
        del temp[0]
        for x in range(0, 2):
            temp[x] = eval(temp[x])
        chu_li.append(temp)
    return chu_li

a280 = pd.read_csv(r'a280.tsp', encoding='utf-8-sig', header=None)
att48 = pd.read_csv(r'att48.tsp', encoding='utf-8-sig', header=None)
ch150 = pd.read_csv(r'ch150.tsp', encoding='utf-8-sig', header=None)
eil76 = pd.read_csv(r'eil76.tsp', encoding='utf-8-sig', header=None)
lin105 = pd.read_csv(r'lin105.tsp', encoding='utf-8-sig', header=None)

city_location=data_deal(att48)
city_num = [i for i in range(len(city_location))] #城市编号
city_count=len(city_num)


origin = 0 #设置起点和终点
remain_cities = city_num[:]
remain_cities.remove(origin)#迭代过程中变动的城市
remain_count = city_count - 1 #迭代过程中变动的城市数
indexs = city_num.remove(origin)
#计算邻接矩阵
dis =[[0]*city_count for i in range(city_count)] #初始化
for i in range(city_count):
    for j in range(city_count):
        if i != j:
            dis[i][j] = math.sqrt((city_location[i][0]-city_location[j][0])**2 + (city_location[i][1]-city_location[j][1])**2)
        else:
            dis[i][j] = 0

def route_mile_cost(route):
    '''
    计算路径的里程成本
    '''
    mile_cost=0+dis[0][route[0]]
    for j in range(remain_count-1):
        mile_cost+=dis[route[j]][route[j+1]]
    mile_cost+=dis[route[remain_count-1]][0]#回家
    return mile_cost

def distance(city_a, city_b):
    # dist代表距离
    x = city_a[0] - city_b[0]
    y = city_a[1] - city_b[1]
    dist = (x ** 2 + y ** 2) ** 0.5
    return dist


def greedy_initial_route():
    temp=city_location[:]
    for i  in range(0,len(temp)-1):
        dis = distance(temp[i], temp[i+1])
        for j in range(i+2,len(temp)):
            t=distance(temp[i],temp[j])
            if  t<dis:
                dis=t
                temp[i+1],temp[j]=temp[j],temp[i+1]
    route=[]
    for i in temp:
        route.append(city_location.index(i))
    del route[0]
    return route

#物竞天择,适者生存
def selection(population):
    '''
    选出父代个体
    '''
    M = population_size
    parents = []
    for i in range(M):
        if random.random() < (1 - i/M):
            parents.append(population[i])
    return parents
def CPX(parent1,parent2):
    '''顺序交叉'''
    dot=random.randint(1, city_count-1)
    behind=parent2[dot:]
    font=[]
    for i in parent1:
        if i not in behind:
            font.append(i)
    child=font+behind
    return child
    '''
    交叉繁殖:CX与PX的混合双亲产生两个子代
    cycle = []
    start = parent1[0]
    cycle.append(start)
    end = parent2[0]
    while end != start:
        cycle.append(end)
        end = parent2[parent1.index(end)]
    child = parent1[:]
    cross_points = cycle[:]
    if len(cross_points) < 2 :
        cross_points = random.sample(parent1,2)
    k = 0
    for i in range(len(parent1)):
        if child[i] in cross_points:
            continue
        else:
            for j in range(k,len(parent2)):
                if parent2[j] in cross_points:
                    continue
                else:
                    child[i] = parent2[j]
                    k = j + 1
                    break  
    return child
    '''
#变异
def mutation(children,mutation_rate):
    '''
    子代变异
    '''
    for e in range(len(children)):
        if random.random() < mutation_rate:
            i=0
            j=0
            while(i==j):#防止随机了同一城市
                i=random.randint(1,remain_count-1)
                j=random.randint(1,remain_count-1)
            child_new=children[e].copy()
            child_new[i:j+1]=list(reversed(child_new[i:j+1]))
            #d1=route_mile_cost(children[e])  #变异后若有改进,则保留,这降低了种群的随机性搜索
            #d2=route_mile_cost(child_new)
            #if d1>d2:
            children[e]=child_new

    return children

def get_best_current(population):
    '''
    将种群的个体按照里程排序,并返回当前种群中的最优个体及其里程
    '''
    graded = [[route_mile_cost(x),x] for x in population]
    graded = sorted(graded)
    population = [x[1] for x in graded]
    mean=sum([x[0] for x in graded])/len(population)
    return graded[0][0],graded[0][1],population,mean

#寻找上一个最优路径对应的所有领域解
def find_newpath(path_best):
    path_new=[]
    for i in range(0,city_count-1):
        for j in range(i+1,city_count-1):
            path=path_best.copy()
            path[i:j+1]=list(reversed(path[i:j+1]))
            path_new.append(path)
    return path_new

#计算所有路径对应的距离
def cal_newpath(dis_mat,path_new):
    dis_list=[]
    for each in path_new:
        t=route_mile_cost(each)
        dis_list.append(t)
    return dis_list

population_size = 100 #种群数
mutation_rate = 0.02 #变异概率
def main(iter_count):
    #初始化种群
    population = [greedy_initial_route()]
    #population = []
    for i in range(population_size-1):
        #随机生成个体
        individual  = remain_cities[:]
        random.shuffle(individual)
        population.append(individual)
    mile_cost,result,population,mean = get_best_current(population)
    record = [mile_cost] #记录每一次繁殖的最优值
    means=[mean]
    iter = 0
    while iter < iter_count:
        #选择繁殖个体群
        parents = selection(population)
        #交叉繁殖
        target_count = population_size - len(parents) #需要繁殖的数量(保持种群的规模)
        children = []
        while len(children) < target_count:
            parent1,parent2 = random.sample(parents,2)
            child1 = CPX(parent1,parent2)
            child2 = CPX(parent2,parent1)
            children.append(child1)
            children.append(child2)

        #父代变异
        parents = mutation(parents,1)
        #子代变异
        children = mutation(children,mutation_rate)
        #更新种群
        population = parents + children
        #对种群中的每个个体采取模拟退火算法搜索局部最优
        ''' 取消注释 并将下方get_best_current的参数改为p_t 此时为遗传+局部搜索
        p_t=[]
        for i in population:
            for j in range(2):#迭代
                #寻找全领域新解
                path_new=find_newpath(i)
                #print(path_new)
                #求出所有新解的路径长度
                dis_new=cal_newpath(dis,path_new)
            #    print(dis_new)
                #选择路径
                dis_best=min(dis_new)#最短距离
                path_best=path_new[dis_new.index(dis_best)]#对应的最短路径方案
                p_t.append(path_best)
        '''
        
        #更新繁殖结果
        mile_cost,result,population,mean = get_best_current(population)
        record.append(mile_cost) #记录每次繁殖后的最优解
        means.append(mean)#记录平均每次迭代的平均解
        iter =iter+1
    route = [origin] + result + [origin]
    return route,mile_cost,record,means

def fig():
    time_start = time.time()
    N = 2000 #进化次数
    satisfactory_solution,mile_cost,record,means = main(N)
    time_end = time.time()
    time_cost = time_end - time_start
    print('time cost:',time_cost)
    print("优化里程成本:%d" %(int(mile_cost)))
    print("优化路径:\n",satisfactory_solution)
    for i in range(1,len(satisfactory_solution)):
        for j in range(i+1,len(satisfactory_solution)):
            if satisfactory_solution[i]==satisfactory_solution[j]:
                print(i)
                print("wrong")
                break
    #绘制路线图
    X = []
    Y = []
    for i in satisfactory_solution:
        plt.scatter(city_location[i][0], city_location[i][1],color='b')
        x = city_location[i][0]
        y = city_location[i][1]
        X.append(x)
        Y.append(y)
    plt.plot(X,Y,'-o')
    plt.title("satisfactory solution of TS:%d"%(int(mile_cost)))
    plt.show()
    #绘制迭代过程图
    A = [i for i in range(N+1)]#横坐标
    B = record[:] #纵坐标
    C=means[:]
    plt.xlim(0,N)
    plt.xlabel('进化次数',fontproperties="SimSun")
    plt.ylabel('路径里程',fontproperties="SimSun")
    plt.title("solution of GA changed with evolution")
    plt.plot(A,B,'b-')
    plt.plot(A,C,'r-')
    plt.legend(["best","average"])
    plt.show()
    return mile_cost,time_cost

fig()

结果展示

常规的遗传算法

数据集运行时间(s)最短距离官方距离
att4833460433533
路线图迭代下降图

常规的遗传算法+局部搜索算法

数据集运行时间(s)最短距离官方距离
att48343372333533
路线图迭代下降图

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值