zoukankan      html  css  js  c++  java
  • 遗传算法解决TSP问题

    旅行商问题,即TSP问题(Traveling Salesman Problem)又译为旅行推销员问题、货郎担问题,是数学领域中著名问题之一。
    假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。
    路径的选择目标是要求得的路径路程为所有路径之中的最小值。

    选用python和matplotlib.pyplot图形化

    import math
    import copy
    import random
    import numpy as np
    import matplotlib.pyplot as plt
    from numpy.lib.function_base import average
    
    class TSP():
        citys_position=[]               #城市坐标
        population=[]                   #种群数组
        fitness=[]                      #适应度数组
        citys_size=10                   #城市个数
        population_size=100             #种群大小
        rate_crossover=0.1             #交叉率
        rate_mutation=0.01              #变异率
        iteration_num=200              #最大迭代次数
        best_dist=0x3f3f3f3f3f          #记录最优距离
        dist_list=[]                    #记录当前距离
        best_dist_list=[]               #记录最优距离    
        best_individual=[]              #记录目前最优旅行方案 
        
        #加载城市坐标
        def load_citys_position(self):
            self.citys_position=[
                [18,54],[87,76],[74,78],[71,71],[25,38],
                [58,35],[4,50],[13,40],[18,40],[24,42],
                # [71,44],[64,60],[68,58],[83,69],[58,69],
                # [54,62],[51,67],[37,84],[41,94],[2,99]
            ]
    
        #加载初始种群
        def load_population(self):
            for i in range(self.population_size):
                temp=[]
                while len(temp)<self.citys_size:
                    ite = random.randint(0,self.citys_size-1)
                    if ite not in temp:
                        temp.append(ite)
                self.population.append([])
                for j in temp:
                    self.population[i].append(j)
            # print(self.population)
    
        #初始化
        def __init__(self):
            self.load_citys_position()
            self.load_population()
            self.get_fitness()
            self.choice()
    
        #城市距离-染色体权值
        def city_dist(self,i,j):
            x=self.citys_position[i]
            y=self.citys_position[j]
            return math.sqrt(pow(x[0]-y[0],2)+pow(x[1]-y[1],2))
    
        #种群距离集
        def population_dist(self):
            now_dist_list=[]
            for i in range(len(self.population)):
                now_dist=0
                for j in range(1,len(self.population[i])):
                        now_dist+=self.city_dist(self.population[i][j],self.population[i][j-1])
                now_dist_list.append(now_dist)
            return now_dist_list
    
        #适应度函数
        def get_fitness(self):
            self.dist_list=self.population_dist()
            now_best_dist=min(self.dist_list)
            now_best_dist_index=self.dist_list.index(now_best_dist)
            now_fitness=[]
            
            if now_best_dist<self.best_dist:
                self.best_dist_list.append(now_best_dist)
                self.best_dist=now_best_dist
                self.best_individual=self.population[now_best_dist_index]
            else :
                self.best_dist_list.append(self.best_dist)
            for i in range(len(self.dist_list)):
                now_fitness.append(self.best_dist/self.dist_list[i])
            self.fitness=now_fitness
            # print("self.best_dist:",self.best_dist," now_dist_list:",now_dist_list)
            # print("self.fitness:",self.fitness)
                        
        #变异
        def mutation(self):
            for i in range(len(self.population)):
                now_rate=random.random()
                if(now_rate<self.rate_mutation):
                    #随机出两个点进行片段翻转
                    index1=random.randint(0,len(self.population[i])-1)
                    index2=random.randint(0,len(self.population[i])-1)
                    if index1>index2:
                        temp=index1
                        index1=index2
                        index2=temp
                    self.population[i][index1:index2]=list(reversed(self.population[i][index1:index2]))
    
        #交叉互换
        def crossover(self):
            last_index=-1;
            for i in range(len(self.population)):
                now_rate=random.random();
                if(now_rate<self.rate_crossover):
                    if(last_index==-1):
                        last_index=i
                    else : #顺序交叉,保留前一个染色体的中间段,交换两端
                        index1=random.randint(0,len(self.population[last_index])-1)
                        index2=random.randint(0,len(self.population[last_index])-1)
                        if index1>index2:
                            temp=index1
                            index1=index2
                            index2=temp
                        temp_list=[]    #取出中间段
                        for j in range(index1,index2+1):
                            temp_list.append(self.population[last_index][j])
                        next_gen=[]  #存储交叉互换后的基因
                        index_temp=0
                        for j in range(len(self.population[i])):                            
                            if self.population[i][j] not in temp_list:
                                next_gen.append(self.population[i][j])
                            else :
                                next_gen.append(temp_list[index_temp])
                                index_temp+=1
                        self.population[last_index]=next_gen  #赋新基因
                        last_index=i;
         #选择函数
        def choice(self):
            #最优解覆盖
            for i in range(len(self.fitness)):
                if self.fitness[i]<0.5:
                    # print("self.fitness[i]:",self.fitness[i]," self.dist_list[i]:",self.dist_list[i]," best_dist:",self.best_dist)
                    # print("self.population[i]:",self.population[i],"self.best_individual:",self.best_individual)
                    # print(" ")
                    self.population[i]=self.best_individual
                    self.fitness[i]=1
                       
        #进化,主函数
        def evolution(self):
            now_iteration_num=0 
            while now_iteration_num<self.iteration_num:
                now_iteration_num+=1
                self.crossover()
                self.mutation()
                self.get_fitness()
                self.choice()
                
    
        #可视化数据
        def plot_show(self):
            print("self.best_dist",end=":")
            print(self.best_dist)
            print("self.best_individual",end=":")
            print(self.best_individual)
            x1=[]
            y1=[]
            x2=[]
            y2=[]
            for i in range(len(self.citys_position)):
                x1.append(self.citys_position[i][0])
                y1.append(self.citys_position[i][1])
            for i in range(len(self.best_individual)):
                x2.append(self.citys_position[self.best_individual[i]][0])
                y2.append(self.citys_position[self.best_individual[i]][1])
            print("x1:",end="")
            print(x1)
            print("y1:",end="")
            print(y1)
            print("x2:",end="")
            print(x2)
            print("y2:",end="")
            print(y2)
            plt.title("citys_position")
            plt.scatter(x1,y1,color='r',marker='o' ); #画点
            plt.figure();
            plt.title("best_route")
            plt.plot(x2,y2,color='r',marker='o' ); #画点
            for i in range(len(x2)):
                plt.text(x2[i],y2[i],i+1)
            plt.figure();
            plt.title("best_dist_change")
            plt.plot(self.best_dist_list,color='r')
            plt.show()
    def main():
        tsp=TSP()
        tsp.evolution()
        tsp.plot_show()
    
    if __name__ == '__main__':
        main()
        
    
  • 相关阅读:
    Python中max()内置函数使用(list)
    linux命令总结mpstat命令
    linux命令总结vmstat命令
    linux命令总结free命令
    linux命令总结top命令
    linux命令总结之echo命令
    Nagios服务器端配置文件详解
    python之OS模块详解
    真正的inotify+rsync实时同步 彻底告别同步慢
    linux BASH shell下设置字体及背景颜色
  • 原文地址:https://www.cnblogs.com/hrdate/p/15470120.html
Copyright © 2011-2022 走看看