遗传算法求解TSP问题

'''
Author: yang youzi
Date: 2023-12-27 11:31:00
LastEditors: yang youzi
LastEditTime: 2023-12-29 20:03:47
FilePath: \Product_planning_and_scheduling-master\GAtrial.py
Description: 1、首先生成邻接矩阵,2、然后生成初始化样本,3、接着选择精英样本,4、再选择可供交叉和变异的样本,5、然后进行交叉和变异重复该国程
'''
import numpy as np
import pandas as pd
import random
import matplotlib.pylab as plt

# 读取tsp坐标文档方法
def readfile():
    file=pd.read_csv("./tsp/dj38.tsp",sep=" ",header=None,skiprows=10)
    file[0]=file[0]-1
    return file


# 计算各城市的邻接矩阵
def generate_distance_matrix(file):
    city_num=len(file)
    # 生成全为0的n*n矩阵
    distance_matrix=np.zeros((city_num,city_num))
    # 将矩阵的值都更新为点的距离,欧氏距离公式
    for i in range(city_num):
        for j in range(city_num):
            x=np.power((file.iloc[i][1]-file.iloc[j][1]),2)
            y=np.power((file.iloc[i][2]-file.iloc[j][2]),2)
            distance_matrix[i][j]=np.sqrt(x+y)
    return distance_matrix


# 初始化种群,生成可能的解
def init_population(file):
    city_num=len(file)
    species=200
    population=[]
    for i in range(species):
        temp_dict=np.random.permutation(range(city_num)).tolist()
        # 加入第一个元素到末尾形成闭环
        temp_dict.append(temp_dict[0])
        if temp_dict not in population:
            population.append(temp_dict)
    return population


# 定义适应度函数,计算单个个体适应度
def fitness(population,distance_matrix):
    total_distance=0
    for i in range(len(population)-1):
        # 下一个地点位置
        k=population[i+1] % len(population)
        total_distance+=distance_matrix[population[i]][k]
    return 1/total_distance



# 交叉方法
def cross(sample1,sample2):
    city_num=len(sample1)
    choice_sample=[i for i in range(city_num)]
    cross_position=random.choice(choice_sample)
    child1=sample1[0:cross_position]
    child2=sample2[0:cross_position]
    child1.extend(sample1[cross_position:city_num])
    child2.extend(sample2[cross_position:city_num])

    temp1=[]
    temp2=[]
    # 对交叉后重复值进行重新整理
    for i in range(cross_position,city_num):
        for j in range(cross_position):
            if child1[i]==child1[j]:
                temp1.append(j)
            if child2[i]==child2[j]:
                temp2.append(i)
    cross_n=len(temp1)
    for k in range(cross_n):
        child1[temp1[k]],child2[temp2[k]]=child2[temp2[k]],child1[temp1[k]]
    return child1,child2


#变异方法
def mutuate(sample):
    sample_len=len(sample)
    chioces=np.random.choice(sample_len,2)
    if chioces[0]>chioces[1]:
        mins=chioces[1]
        maxs=chioces[0]
    else:
        mins=chioces[0]
        maxs=chioces[1]
    resultsample=sample[0:mins]
    midsample=list(reversed(sample[mins:maxs]))
    resultsample.extend(midsample)
    resultsample.extend(sample[maxs:])
    return resultsample

# 生成选择概率
def compute_choice_prob(populations,distance_matrix):
    prob_list=[]
    for i in range(len(populations)):
        prob_list.append(fitness(populations[i],distance_matrix))
    sig=sum(prob_list)
    choice_prob = (prob_list / sig).tolist()
    return choice_prob

# 选择需要进行交叉和变异的样本
def choice_newsample(species,initx,choice_prob):
    # 重新选择样本
    newx=[]
    index = [i for i in range(species)]
    news = random.choices(index,weights=choice_prob,k=int(0.8*species))
    newsnum = len(news)
    for i in range(newsnum):
        newx.append(initx[news[i]])
    return newx

# 选择精英样本
def choice_elite(species,choice_prob,population):
    topk=int(species*0.2)
    num_dict = {}
    for i in range(len(choice_prob)):
        num_dict[i] = choice_prob[i]
    res_list = sorted(num_dict.items(),key=lambda e:e[1]) #e[1]表示按值排序,e[0]表示按键排序
    elite = [one[0] for one in res_list[::-1][:topk]]
    elite_list=[]
    for i in elite:
        elite_list.append(population[i])
    return elite_list

def main():
    file=readfile()
    distance_matrix=generate_distance_matrix(file)
    init_populations=init_population(file)
    species=200
    inters=5000
    populations=init_populations
    result=[]
    cts=[]
    for inter in range(inters):
        # 计算样本适应度值
        choice_prob=compute_choice_prob(populations,distance_matrix)
        # 计算选择的精英样本
        elite_population=choice_elite(species,choice_prob,populations)
        # 计算选择的变异样本
        choice_newsamples=choice_newsample(species,populations,choice_prob)
        # 对变异样本进行变异选择
        num=int(len(choice_newsamples)/2)
        for i in range(num):
            j=i+num-1
            if random.choice([1,2,3,4,5,6,7,8,9,10])<8:
                sample1=choice_newsamples[i][0:len(populations[0])-1]
                sample2=choice_newsamples[j][0:len(populations[0])-1]
                sample1,sample2=cross(sample1,sample2)
                if random.choice([1,2,3,4,5,6,7,8,9,10])<4:
                    sample1=mutuate(sample1)
                    sample2=mutuate(sample2)
                sample1.append(sample1[0])
                sample2.append(sample2[0])
                choice_newsamples[i],choice_newsamples[j]=sample1,sample2
        populations=[]
        populations.extend(elite_population)
        populations.extend(choice_newsamples)
        res=[]
        for k in range(len(populations)):
            res.append(fitness(populations[k],distance_matrix))
        result.append(1/max(res))
        cts.append(inter)

    return populations,result,cts
    

if __name__=='__main__':
    file=readfile()
    populations,result,cts=main()
    graph1=[]
    graph2=[]
    for i in range(len(populations[0])):
        graph1.append(file.iloc[populations[0][i],1])
        graph2.append(file.iloc[populations[0][i],2])
    plot=plt.plot(graph1,graph2,c='r')
    plt.xlabel('x')
    plt.ylabel('y')
    plt.show()
    print(cts,result)
    plot = plt.plot(cts, result)
    plt.xlabel('inters')
    plt.ylabel('distance')
    plt.show()
    

1、题目内容:求解最短路径

2、 数据下载地址:http://www.math.uwaterloo.ca/tsp/world/countries.html#DJ

3、最短路径如下:

4、迭代效果如下:

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值