遗传算法解决TSP(34个省会城市)问题

主要是参考了https://blog.csdn.net/qq_14809723/article/details/79013691这篇文章,完善了一定的小功能。

本代码可以完善的功能有1、选择算子方面,轮盘赌误差比较大,可以采取最优保存和排序选择策略。2、交叉和突变算子方面可以采取其他方法 3、绘图方面 只是简单的描点连线

import random
import math
from math import radians, cos, sin, asin, sqrt
import matplotlib.pyplot as plt

# 计算两省会城市之间的距离 x经度  y维度
def Distance(x1, y1,x2,y2):
    x1, y1, x2, y2 = map(radians, [x1, y1, x2, y2])
    disx = x1-x2
    disy = y1-y2
    a = sin(disy/2)**2 + cos(y1)* cos(y2)* sin(disx/2)** 2
    dis = 2* asin(sqrt(a)) * 6371
    return dis

SCORE_NONE = -1

#单个城市个体信息
class Life(object):

    def __init__(self,aGene = None):
        self.gene = aGene
        self.score = SCORE_NONE

#遗传算法
class GA(object):

    def __init__(self, aCrossRate, aMutationRate, aLifeCount, aGeneLength, aMatchFun):
       # 交叉概率
       self.crossrate = aCrossRate
       # 突变概率
       self.mutationrate = aMutationRate
       # 种群大小
       self.lifecount = aLifeCount
       # 基因长度
       self.genelength = aGeneLength
       # 适应度函数
       self.matchfun = aMatchFun
       # 种群数组
       self.lives = []
       # 最优个体 选择
       self.best = None
       # 代数
       self.generation = 1
       # 交叉计数
       self.crosscount = 0
       # 变异计数
       self.mutationcount = 0
       # 适应度之和  判定选择概率
       self.masum = 0.0
       # 适应度平均值
       self.mean = 1.0
       self.initPopulation()

    # 初始化种群
    def initPopulation(self):
        self.lives = []
        # 对序列随机排序
        for i in range(self.lifecount):
            gene = [x for x in range(self.genelength)]
            random.shuffle(gene)
            life = Life(gene)
            self.lives.append(life)

    # 适应度函数
    def judge(self):

        # 计算每一个个体的适应度
        self.masum = 0.0
        self.best = self.lives[0]
        for life in self.lives:
            life.score = self.matchfun(life)
            self.masum += life.score
            if self.best.score < life.score:
                self.best = life
        self.mean = self.masum / self.lifecount

    # 交叉算子
    def cross(self, dad, mom):
        n = 0
        while 1:
            newGene = []

            # 生成交叉范围
            index1 = random.randint(0, self.genelength-1)
            index2 = random.randint(index1, self.genelength -1)
            tempGene = mom.gene[index1:index2]

            #交叉
            p1len = 0
            for g in dad.gene:
                if p1len == index1:
                    newGene.extend(tempGene)
                    p1len +=1
                if g not in tempGene:
                    newGene.append(g)
                    p1len +=1
            if(self.matchfun(Life(newGene)) > max(self.matchfun(dad), self.matchfun(mom))):
                self.crosscount +=1
                return newGene
            if (n > 100):
                self.crosscount +=1
                return newGene
            n += 1

    # 突变算子
    def mutation(self, wang):

         #产生新的基因序列
         index1 = random.randint(0, self.genelength - 1)
         index2 = random.randint(0, self.genelength - 1)
         newGene = wang.gene[:]
         newGene[index1], newGene[index2] = newGene[index2], newGene[index1]
         if self.matchfun(Life(newGene)) > self.matchfun(wang):
             self.mutationcount += 1
             return newGene
         else:
             rate = random.random()
             if rate < math.exp(-10 / math.sqrt(self.generation)):
                 self.mutationcount +=1
                 return  newGene
             return wang.gene

    # 选择某个体
    def choose(self):

        # 随机采样
        r = random.uniform(0, self.masum)

        # 轮盘赌方法
        for life in self.lives:
            r -= life.score
            if r <= 0:
                return life
        raise  Exception("选择错误", self.masum)

    # 产生后代
    def child(self):
        dad = self.choose()

        # 概率交叉
        rate = random.random()
        if rate < self.crossrate:
            mom = self.choose()
            gene = self.cross(dad, mom)
        else:
            gene = dad.gene

        # 概率突变
        rate = random.random()
        if rate < self.mutationrate:
            gene = self.mutation(Life(gene))
        return Life(gene)

    # 产生下一代
    def next(self):
        self.judge()
        newLives = []

        # 把最好的加入下一代
        newLives.append(self.best)
        while len(newLives) < self.lifecount:
            newLives.append(self.child())
        self.lives = newLives
        self.generation +=1

# TSP类
class TSP(object):
    def __init__(self, aLifeCount = 100):
        self.initCitys()
        self.lifeCount = aLifeCount
        self.ga = GA(aCrossRate=CROSSRATE,
                     aMutationRate=MUTATIONRATE,
                     aLifeCount=self.lifeCount,
                     aGeneLength=len(self.citys),
                     aMatchFun=self.matchFun())

    # 省会城市经纬度
    def initCitys(self):
        self.citys = []
        self.citys.append((116.46, 39.92))
        self.citys.append((117.2, 39.13))
        self.citys.append((121.48, 31.22))
        self.citys.append((106.54, 29.59))
        self.citys.append((91.11, 29.97))
        self.citys.append((87.68, 43.77))
        self.citys.append((106.27, 38.47))
        self.citys.append((111.65, 40.82))
        self.citys.append((108.33, 22.84))
        self.citys.append((126.63, 45.75))
        self.citys.append((125.35, 43.88))
        self.citys.append((123.38, 41.8))
        self.citys.append((114.48, 38.03))
        self.citys.append((112.53, 37.87))
        self.citys.append((101.74, 36.56))
        self.citys.append((117, 36.65))
        self.citys.append((113.65, 34.76))
        self.citys.append((118.78, 32.04))
        self.citys.append((117.27, 31.86))
        self.citys.append((120.19, 30.26))
        self.citys.append((119.3, 26.08))
        self.citys.append((115.89, 28.68))
        self.citys.append((113, 28.21))
        self.citys.append((114.31, 30.52))
        self.citys.append((113.23, 23.16))
        self.citys.append((121.5, 25.05))
        self.citys.append((110.35, 20.02))
        self.citys.append((103.73, 36.03))
        self.citys.append((108.95, 34.27))
        self.citys.append((104.06, 30.67))
        self.citys.append((106.71, 26.57))
        self.citys.append((102.73, 25.04))
        self.citys.append((114.1, 22.2))
        self.citys.append((113.33, 22.13))

    # 计算总里程
    def distance(self, order):
        distance = 0.0
        for i in range(-1, len(self.citys) - 1):
            index1, index2 = order[i], order[i+1]
            city1, city2 = self.citys[index1], self.citys[index2]
            distance += Distance(city1[0], city1[1], city2[0], city2[1])
        return distance

    # 适应度函数  距离的倒数
    def matchFun(self):
        return lambda life: 1.0/self.distance(life.gene)

    # 主函数
    def main(self, n = 0):
        while n > 0:
            self.ga.next()
            distance = self.distance(self.ga.best.gene)

            # 输出当前代数和路径长度
            print(("Generation: %4d \t\t Distance: %f") % (self.ga.generation - 1, distance))

            # 输出最佳路径
            self.ga.best.gene.append(self.ga.best.gene[0])
            print("Path: ", self.ga.best.gene)
            self.ga.best.gene.pop()
            n -= 1

# 绘图
def draw(bestPath, cities):
    ax = plt.subplot(111, aspect = 'equal')
    x = []
    y = []
    for i in range(-1, len(cities) - 1):
        index = bestPath[i]
        city = cities[index]
        x.append(city[0])
        y.append(city[1])
    x.append(x[0])
    y.append(y[0])
    ax.plot(x, y)
    plt.show()

# 主函数
if __name__ == '__main__':

    # 迭代次数
    num = input("请输入迭代次数:")
    num = int(num)

    # 交叉与突变概率
    global CROSSRATE
    global MUTATIONRATE
    CROSSRATE = input("请输入交叉概率:")
    CROSSRATE = float(CROSSRATE)
    MUTATIONRATE = input("请输入突变概率:")
    MUTATIONRATE = float(MUTATIONRATE)

    # 初始序列
    bp = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33]
    tsp=TSP()
    print("初始路径长度:", tsp.distance(bp))

    tsp.main(num)
    draw(tsp.ga.best.gene, tsp.citys)
  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值