首页 > 编程语言 >TSP问题的各种解法(Python)

TSP问题的各种解法(Python)

时间:2023-11-05 10:33:46浏览次数:46  
标签:bestway dna dnat Python TSP range 解法 11225 best

#coding=utf-8
import matplotlib.pyplot as plt
import math
import time
import random


x = [4475,4475,4475,4475,5450,5475,5475,4575,5425,5425,5425,5425,5425,6000,6375,6000,6375,6475,6475,6475,6475,6100,6350,6350,6100,6550,5775,6075,6375,6375,6075,5775,6975,6675,6675,6875,6850,6600,6600,6850,7100,7100,7100,7100,7100,6925,6925,6925,6925,6925,6925,7700,7850,7700,7750,8125,8500,8500,7600,8350,7975,8350,9375,9531,9475,9275,10375,9687,9843,9999,10155,10311,10467,10623,10779,10935,11091,11247,11403,11559,11175,11275,10650,11275,11125,11025,11000,11000,11650,11725,12500,11715,11871,12027,12183,12339,12495,12651,12807,12963,13325,13100,12825,12850,13585,13585,13585,13585,13585,13585,13585,13585,13585,13585,13585,13585,13585,13585,13585,13585,13585,13585,13585,13585]
y = [8657,8969,9407,9719,10475,9750,8650,8425,3300,3000,2400,2100,1800,2375,2375,3375,3375,4675,4875,5275,5475,6675,6675,7275,7275,7625,8650,8650,8650,9750,9750,9750,9750,9750,8650,8650,7275,7275,6675,6675,5425,5275,5075,4875,4675,3300,3000,2700,2400,2100,1800,3725,3700,4725,7475,7525,7475,8225,9025,9025,9075,9775,11225,11225,10275,10050,9525,11225,11225,11225,11225,11225,11225,11225,11225,11225,11225,11225,11225,11225,9800,9475,9400,9175,5350,4750,4600,3600,3350,4825,5950,11225,11225,11225,11225,11225,11225,11225,11225,11225,6100,4625,3800,2425,1975,2131,2287,2443,2599,2755,2911,3067,3223,3379,9615,9771,9927,10083,10239,10395,10551,10707,10863,11019]
n = len(x)
bestway = [i for i in range(n)]
dis_array = [[0]*n for i in range(n)]



#绘制最优路径
def draw_bestway():
    best_x = []
    best_y = []

    for i in range(n):
        p = bestway[i]
        best_x.append(x[p])
        best_y.append(y[p])
    best_x.append(best_x[0])
    best_y.append(best_y[0])
    plt.rcParams['font.sans-serif'] = 'SimHei'
    plt.title("TSP图解")
    plt.plot(best_x,best_y,color="green",linestyle="-",marker="o",markerfacecolor="red")
    plt.show()

##计算最优路径分值
def comp_bestway_score():
    best_x = []
    best_y = []

    for i in range(n):
        p = bestway[i]
        best_x.append(x[p])
        best_y.append(y[p])
    value=0.0
    for i in range(1,n):
        x2 = (best_x[i - 1] - best_x[i]) * (best_x[i - 1]-best_x[i])
        y2 = (best_y[i - 1] - best_y[i]) * (best_y[i - 1] - best_y[i])
        value = value + math.sqrt(x2 + y2)
    x2 = (best_x[0] - best_x[n - 1]) * (best_x[0] - best_x[n - 1])
    y2 = (best_y[0] - best_y[n - 1]) * (best_y[0] - best_y[n - 1])
    value = value + math.sqrt(x2 + y2)
    return(value)


##建立距离矩阵
def build_dis_array():
    for i in range(n):
        for j in range(n):
            dis_array[i][j]=math.sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]))
#打印距离矩阵
def print_dis_array():
    for i in range(n):
        for j in range(n):
            print('%.2f' % dis_array[i][j], end=',')
        print()


#贪心算法求解TSP
def greedy():
    #选择相邻距离最近的两个结点作为最初的线段
    min_dis = 10000
    way = []
    run_array = [[0]*n for i in range(n)]#复制距离矩阵,在该矩阵上寻找新的最短路径结点
    for i in range(n):
        for j in range(n):
            run_array[i][j] = dis_array[i][j]
    #在运行矩阵上寻找相邻距离最近的两个结点
    for i in range(1,n):
        for j in range(i):
            if(run_array[i][j]>0 and run_array[i][j]<min_dis):
                min_dis=run_array[i][j]
                min_a=i
                min_b=j
    way.append(min_a)
    way.append(min_b)
    run_array[min_a][min_b]=0#访问过的路径在矩阵中置0,禁止再次访问
    run_array[min_b][min_a]=0#访问过的路径在矩阵中置0,禁止再次访问
    #从两端在未访问的结点中选择最近的结点扩展,直到所有结点均已访问
    for i in range(n-2):
        min_dis=10000
        # 搜索与当前路径最左侧结点相邻的结点,寻找最近的结点
        for j in range(n):
            if(run_array[j][way[0]]>0 and run_array[j][way[0]]<min_dis):
                min_dis = run_array[j][way[0]]
                min_a = j
                min_b = way[0]
        # 搜索与当前路径最右侧结点相邻的结点,寻找最近的结点
        for j in range(n):
            if(run_array[way[len(way)-1]][j]>0 and run_array[way[len(way)-1]][j]<min_dis):
                min_dis = run_array[way[len(way)-1]][j]
                min_a = way[len(way)-1]
                min_b = j
        # 如果最近的结点是在右端,则插入右端,并将新变成中间结点的原尾结点与其他所有结点距离置0,表示不可访问
        if(min_a==way[len(way)-1]):
            way.append(min_b);run_array[way[0]][min_b]=0;run_array[min_b][way[0]]=0
            for j in range(n):
                run_array[min_a][j]=0;run_array[j][min_a]=0
        # 如果最近的结点是在左端,则插入左端,并将新变成中间结点的原头结点与其他所有结点距离置0,表示不可访问
        else:
            way.insert(0,min_a);run_array[way[len(way)-1]][min_a]=0;run_array[min_a][way[len(way)-1]]=0
            for j in range(n):
                run_array[min_b][j]=0;run_array[j][min_b]=0
    for i in range(n):
        bestway[i]=way[i]
        
#模拟退火算法
#利用温度控制逐步减少接受差解的概率,最终达到局部最优
def sa():
    obway = [0]*n#保存当前全局最优解
    t = 20
    tf = 0.001
    obscore = comp_bestway_score() #obscore保存全局最优值
    for i in range(n):
        obway[i] = bestway[i]
    f1 = obscore#f1保存当前解分值
    while t > tf :
        for iter in range(10):# iter为等温过程迭代次数
            v1 = random.randint(0,n-1)
            v2 = random.randint(0,n-1)
            if(v1!=v2):#随机选择两个不同的结点
                bestway[v1],bestway[v2]= bestway[v2],bestway[v1]#交换随机选择的两个节点
                f2 = comp_bestway_score()#计算候选解的分值,f2保存候选解
                if(f2 < obscore):#如果候选解分值优于全局最优解,则更新全局最优解
                    obscore = f2
                    for i in range(n):
                        obway[i]=bestway[i]
                delta = f2 -f1#计算候选解与当前解之间的差值
                alpha = random.random()
                if(delta<0):#直接接受候选解
                    f1 = f2
                elif(alpha < math.exp(-delta / t)):#根据Metropolis准则接受交换
                    f1 =f2
                else:#不接受候选解,回退到当前解
                    bestway[v2], bestway[v1] = bestway[v1],bestway[v2]
        t = t * 0.995#降温

#禁忌算法
def tabu():
    tabu_long=5;
    tabulist=[[0]*n for i in range(n)]
    obway=[0]*n
    way=[0]*n
    better_way=[0]*n
    for i in range(n):
        obway[i]=bestway[i]
        way[i]=bestway[i]
    obscore=comp_bestway_score()
    for iter in range(200):
        bestscore=10000
        for a in range(1,n):
            for b in range(a):
                for i in range(n):
                    bestway[i]=way[i]
                bestway[a],bestway[b]=bestway[b],bestway[a]
                score=comp_bestway_score()
                if(score < obscore):
                    obscore=score
                    for i in range(n):
                        obway[i]=bestway[i]
                    bestscore=score;v1=a;v2=b
                elif(score<bestscore and tabulist[a][b]==0):
                    bestscore = score;
                    v1=a;v2=b
        way[v1],way[v2]=way[v2],way[v1]
        for i in range(n):
            for j in range(n):
                if(tabulist[i][j]>0):
                    tabulist[i][j]=tabulist[i][j]-1
        tabulist[v1][v2]=tabu_long
        tabulist[v2][v1]=tabu_long
    for i in range(n):
        bestway[i]=obway[i]
#遗传算法
def genetic():
    dna = [[0]*n for i in range(10)]#保存10条dna所代表的可行解
    score = [0]*10 #保存10个可行解的对应分值
    dnat = [[0]*n for i in range(8)]#临时存放交叉变异过程中的dna
    # (0-1保存原始dna,2-3保存交叉后dna,4-7保存突变后dna)
    for i in range(10):#随机生成10条dna初始解
        visit = [0]*n # 保存访问记录,0代表未访问,1代表已访问
        inway = 0 # 记录已访问的结点数
        while inway < n :
            v = random.randint(0,n-1)
            if(visit[v]==0):
                dna[i][inway] = v
                visit[v] = 1
                inway = inway + 1
    for i in range(10): # 计算10条dna的个体分值
        for j in range(n):
            bestway[j] = dna[i][j]
        score[i]=comp_bestway_score()
    sortscore = []#保存排序后的可行解分值
    sortsite = []#保存排序后分值对应的dna号
    for i in range(10):#每次从后面取一个插入到前面排好的序列中
        for j in range(i+1):#插入排序由小到大建立dna排序列表
            if(j>=i or sortscore[j]>score[i]):
                break
        sortscore.insert(j,score[i])
        sortsite.insert(j,i)

    for iter in range(500):
        '''按照概率选择两条dna,保证两条dna不同
        对选取的两条dna进行交叉操作,生成两条新的dna
        对四条dna进行变异操作
        从原始和交叉、变异后的八条dna中选择两条最优dna更新原始dna
        对新的种群重新排序'''
        '''选择'''
        r = random.randint(0,54)
        if(r<10):
            n1 = sortsite[0]
        elif(r<19):
            n1 = sortsite[1]
        elif(r<27):
            n1 = sortsite[2]
        elif(r<34):
            n1 = sortsite[3]
        elif(r<40):
            n1 = sortsite[4]
        elif(r<45):
            n1 = sortsite[5]
        elif(r<49):
            n1 = sortsite[6]
        elif(r<52):
            n1 = sortsite[7]
        elif(r<54):
            n1 = sortsite[8]
        else:
            n1 = sortsite[9]
        n2 = n1
        while(n1==n2): #反复选择,直到选择的第2条dna与第1条不同
            r = random.randint(0, 54)
            if (r < 10):
                n2 = sortsite[0]
            elif (r < 19):
                n2 = sortsite[1]
            elif (r < 27):
                n2 = sortsite[2]
            elif (r < 34):
                n2 = sortsite[3]
            elif (r < 40):
                n2 = sortsite[4]
            elif (r < 45):
                n2 = sortsite[5]
            elif (r < 49):
                n2 = sortsite[6]
            elif (r < 52):
                n2 = sortsite[7]
            elif (r < 54):
                n2 = sortsite[8]
            else:
                n2 = sortsite[9]

        '''交叉'''
        for i in range(n):#将随机选择的两条dna保存在dnat[0]和dnat[1]中
            dnat[0][i]= dna[n1][i]
            dnat[1][i] = dna[n2][i]
            # 随机选择交叉片段的两个端点,保证端点不相同且片段不为整个dna序列
        tag = 0#标记端点选择未完成
        while(tag == 0):
            c1 = random.randint(0, n-1)
            c2 = random.randint(0, n-1)
            if(c1==c2):
                continue
            if(c1>c2):
                c1,c2=c2,c1 #保证c1在前、c2在后
            if(c1==0 and c2==123):
                continue
            tag=1
        '''将dnat[0]中c1到c2之外的基因,用dnat[1]的基因顺序填充(顺序交叉法),保证基因不
        重复,交叉的结果存入dnat[2]
        中'''
        v = 0 #记录dna1[1]当前插入基因的位置
        for i in range(c1):#对dnat[2]中c1前的基因从dnat[1]中顺序插入
            insert = 0#记录当前位置基因是否插入成功,insert=0代表未插入成功
            while insert == 0:
                find = 0 #标记当前基因v是否与c1-c2中的基因冲突,find=0代表未发现冲突
                for j in range(c1,c2+1):
                    if(dnat[1][v]==dnat[0][j]):
                        find = 1
                        break
                if(find==0):
                    dnat[2][i] = dnat[1][v]
                    insert = 1
                v = v+1
        for i in range(c1,c2+1):#对dnat[2]中c1-c2基因从dnat[0]中对应位置复制
            dnat[2][i]=dnat[0][i]
        for i in range(c2+1,n):#对dnat[2]中c2后的基因从dnat[1]中顺序插入
            insert = 0 #记录当前位置基因是否插入成功,insert=0代表未插入成功
            while insert == 0:
                find = 0 #标记当前基因v是否与c1-c2中的基因冲突,find=0代表未发现冲突
                for j in range(c1,c2+1):
                    if(dnat[1][v]==dnat[0][j]):
                        find = 1
                        break
                if(find==0):
                    dnat[2][i] = dnat[1][v]
                    insert = 1
                v = v+1

        v = 0
        for i in range(c1):
            insert = 0
            while insert == 0:
                find = 0
                for j in range(c1,c2+1):
                    if(dnat[0][v]==dnat[1][j]):
                        find = 1
                        break
                if(find==0):
                    dnat[3][i] = dnat[0][v]
                    insert = 1
                v = v+1
        for i in range(c1,c2+1):
            dnat[3][i]=dnat[1][i]
        for i in range(c2+1,n):
            insert = 0
            while insert == 0:
                find = 0
                for j in range(c1,c2+1):
                    if(dnat[0][v]==dnat[1][j]):
                        find = 1
                        break
                if(find==0):
                    dnat[3][i] = dnat[0][v]
                    insert = 1
                v = v + 1
        '''变异'''
        for i in range(4):
            for j in range(n):
                dnat[i+4][j]=dnat[i][j]
        for i in range(4,8):
            tag = 0
            while tag==0:
                v1 = random.randint(0,n-1)
                v2 = random.randint(0,n-1)
                if(v1!=v2):
                    dnat[i][v1],dnat[i][v2]=dnat[i][v2],dnat[i][v1]
                    tag = 1
        tscore = [0]*8
        tsortscore = [0]*8
        tsortsite  = [0]*8
        for i in range(8):
            for j in range(n):
                bestway[i]=dnat[i][j]
            tscore[i]=comp_bestway_score()
        for i in range(8):
            tsortscore[i]=tscore[i]
        tsortscore.sort()
        for i in range(8):
            tsortsite[i]= tscore.index(tsortscore[i])
        for i in range(n):
            dna[n1][i]=dnat[tsortsite[0]][i]
            dna[n2][i]=dnat[tsortsite[1]][i]
        for i in range(10):
            for j in range(n):
                bestway[j] = dna[i][j]
            score[i]=comp_bestway_score()
        sortscore = []
        sortsite = []
        for i in range(10):
            for j in range(i+1):
                if(j>=i or sortscore[j]>score[i]):
                    break
            sortscore.insert(j,score[i])
            sortsite.insert(j,i)

#蚁群算法
def antcolony():
    m=100#蚂蚁数
    q=100#一只蚂蚁巡回一次释放的信息素总量
    t=0.4#挥发率
    x=q/n #计算每个城市的平均信息素浓度
    pheromone = [[x] * n for i in range(n)]  # 信息素浓度矩阵
    #print(pheromone)
    obscore=10000#保存当前全局最优分值
    obway=[0]*n# 保存当前全局最优解
    for iter in range(100):
        road=[[0]*n for i in range(m)]#保存m只蚂蚁的对n个城市巡回路线
        vc=[[0]*n for i in range(m)]# 保存m只蚂蚁已经访问过的城市,0代表未访问
        # 随机选择m只蚂蚁的出发城市
        for i in range(m):
            v=random.randint(0,n-1)
            road[i][0]=v#记录起始城市
            vc[i][v]=1#该城市已经访问
        for i in range(n-1):#遍历剩下的n-1个城市
            for j in range(m):#遍历m只蚂蚁
                v=road[j][i]#取出当前城市
                # 保存当前城市到其他城市的权重
                weight=[0]*n
                p=[0]*n#保存每个城市的选择概率
                tolweight = 0  # 保存总权重
                for k in range(n):#遍历未访问城市计算权重
                    if(vc[j][k]!=1):
                        weight[k]=pheromone[v][k]/dis_array[v][k]
                    else:
                        weight[k]=0
                    tolweight=tolweight+weight[k]
                if(tolweight==0):#当总权重为0,代表所有城市均已访问过
                    break
                else:
                    for k in range(n):#计算各城市的选择概率
                        p[k]=weight[k]/tolweight
                r=random.random()
                wheel=0
                for k in range(n):
                    wheel=wheel+p[k]
                    if(wheel>=r):
                        break
                road[j][i+1]=k
                vc[j][k]=1

        roadscore=[0]*m
        for i in range(m):
            for j in range(n):
                bestway[j]=road[i][j]
            roadscore[i]=comp_bestway_score()
            if(roadscore[i]<obscore):
                obscore=roadscore[i]
                for k in range(n):
                    obway[k]=bestway[k]
        for i in range(n):
            for j in range(n):
                pheromone[i][j]=t*pheromone[i][j]
        for i in range(m):
            for j in range(n-1):
                v1=road[i][j]
                v2=road[i][j+1]
                pheromone[v1][v2]=pheromone[v1][v2]+q/roadscore[i]
                pheromone[v2][v1]=pheromone[v2][v1]+q/roadscore[i]
            v1=road[i][n-1]
            v2=road[i][0]
            pheromone[v1][v2]=pheromone[v1][v2]+q/roadscore[i]
            pheromone[v2][v1]=pheromone[v2][v1]+q/roadscore[i]







print("number:",n)
print("init bestway:")
print("bestway",bestway)
print("score:",comp_bestway_score())
draw_bestway()

build_dis_array()
print_dis_array()

time_start=time.time()
print("\nGreedy:")
greedy()
#print("\nsa:")
#sa()
#print("\ntabu:")
#tabu()
#print("\ngenetic:")
#genetic()
#print("\nantcolony:")
#antcolony()
print("bestway",bestway)
print("score:",comp_bestway_score())
time_end=time.time()
print("totally time:",time_end-time_start)
draw_bestway()

标签:bestway,dna,dnat,Python,TSP,range,解法,11225,best
From: https://blog.51cto.com/u_16342340/8190612

相关文章

  • 自然语言处理历史史诗:NLP的范式演变与Python全实现
    本文全面回顾了自然语言处理(NLP)从20世纪50年代至今的历史发展。从初创期的符号学派和随机学派,到理性主义时代的逻辑和规则范式,再到经验主义和深度学习时代的数据驱动方法,以及最近的大模型时代,NLP经历了多次技术革新和范式转换。文章不仅详细介绍了每个阶段的核心概念和技术,还提供......
  • Python学习心得
    python学习心得与体会在我学习Python编程语言的过程中,我收获了很多宝贵的经验和体会。Python是一门强大而又简洁的编程语言,具有广泛的应用领域和丰富的资源支持。通过学习Python,我深刻理解了编程的基本原理和思维方式,并能够灵活运用Python解决实际问题。一、Python简介Python是......
  • python 进程池pool.map
    frommultiprocessingimportPooldefdouble(x):print(x**2)returnx**2if__name__=='__main__':pool=Pool()pool.map(double,list(range(11)))print(list(map(double,list(range(11)))))输出01492516364964100810......
  • [Python急救站]文本进度条
    完游戏的朋友们,是不是看到那种加载加载进度条,感觉特别不错呢,所以今天就来看看文本进度条怎么做。1.基本的多行文本进度条importtimescale=10#变量scale表示输出进度条的精度print("------执行开始------")foriinrange(scale+1):a,b='**'*i,'..'*(sc......
  • python面向对象-学习笔记(八、综合案例)
    计算器,实现一些基本的操作,加减乘除运算,以及打印结果操作点击查看代码importwin32com.clientclassCaculator:#装饰器私有def__check_num_zsq(func):definner(self,n):ifnotisinstance(n,int):raiseTypeError("......
  • python实现手势识别的示例(入门)
    原文:https://pythonjishu.com/yoprvijnxxyihab/手势识别是计算机视觉领域的一个重要研究方向。在实际应用中,手势识别可以被用于人机交互、智能家居控制等领域。在本文中,我们将介绍如何使用Python实现手势识别的示例代码。环境搭建安装Python要使用Python进行手势识别的开发,首......
  • 升级linux下的python版本
    以centos7为例将python升级到3.10.111、安装必备软件包:##第一步基础包yum-yinstallzlib-develbzip2-developenssl-develncurses-develsqlite-develreadline-develtk-develgdbm-devellibpcap-develxz-develgcc##第二步安装db4-devel,必先安装epel-releaseyumi......
  • Python 潮流周刊#25:性能最快的代码格式化工具 Ruff!
    你好,我是猫哥。这里每周分享优质的Python、AI及通用技术内容,大部分为英文。标题取自其中一则分享,不代表全部内容都是该主题,特此声明。本周刊由Python猫出品,精心筛选国内外的250+信息源,为你挑选最值得分享的文章、教程、开源项目、软件工具、播客和视频、热门话题等内容。愿......
  • 【python进阶】14大模块200页知识体系md笔记,第4篇:linux命令进阶(2)
    本文从14大模块展示了python高级用的应用。分别有Linux命令,多任务编程、网络编程、Http协议和静态Web编程、html+css、JavaScript、jQuery、MySql数据库的各种用法、python的闭包和装饰器、mini-web框架、正则表达式等相关文章的详细讲述。完整版笔记直接地址:请移步这里共14......
  • Python02
    判断语句bool类型#bool类型bool_1=Truebool_2=Falseprint(f"bool_1变量的内容是:{bool_1},类型是:{type(bool_1)}")print(f"bool_2变量的内容是:{bool_2},类型是:{type(bool_2)}")#比较运算符的使用#==,!=,>,<,>=,<=num1=10num2=10print(f"10==10的结果是:{nu......