一.题目要求
用最小生成树结合所提供的论文解决旅行商问题。
二.思路分析
Step1:用Prim算法生成最小生成树
Step2:根据最小生成树中各边的权重及各点的度,从大到小对最小生成树进行剪枝操作,使各点的度为0或1。这个功能在程序中使用函数jianzhi实现的。
Step3:将剪枝的结果连接成环,这个功能在程序中使用cicle函数实现。需要分为3步:
第一步:连接度为0的孤立点,使各点的度大于0,连接成一个个子图
第二步:处理当度为1的点数大于2的情况,将各子图连接为一条链
第三步:连接剩下的两个度为1的点,成为一个环
三.实验程序
# -*-coding:gbk-*-
from numpy import *
import Graph #Graph邻接矩阵类,使用到的功能:.out_edges提供连接节点表(连接节点,权重)///.vertex_num获得顶点数
import PrioQueue #基于堆结构实现优先队列的类
from Graph import Graph
from PrioQueue import PrioQueue
##############################最小生成树算法
def Prim(graph):
vnum = graph.vertex_num()#顶点数
mst = [None]*vnum #最小生成树边表,每个元素的形式为((i,j)w),初始所有点都不属于U,为None。最小生成树原则上有n-1条边,为实现方便,加入了((0,0,),0),共有n条
cands = PrioQueue([(0, 0, 0)]) # 记录候选最短边,形式为(w, vi, vj),vi到vj的权重为w。元组的大小比较逐个比较各个元素,这里首先比较w
count = 0#记录最小生成树顶点数
# 第一次迭代将设置 mst[0] = ((0, 0), 0),不必专门写
while count < vnum and not cands.is_empty():#顶点数为n或发现网络不连通
w, u, v = cands.dequeue() # 顶端弹出,向下筛选,取当时的最短边的(w,i,j)
if mst[v]: #该顶点已加入最小生成树,边表非空
continue # 邻接顶点v已在mst,跳出本次循环继续,弃掉该边
mst[v] = ((u, v), w) # 记录新的MST边和顶点
count += 1
for vi, w in graph.out_edges(v): # 考虑v的邻接顶点vi,某行连接节点表[(节点,权重)。。。]
if not mst[vi]: # 如果对已知在U中的v,相邻接的vi不在U中,则将这条边列入侯选边
cands.enqueue((w, v, vi))#尾端插入,向上筛选
return mst
##############################剪枝
def jianzhi(tree):#最小生成树tree((i,j),S)
tree.remove(((0, 0), 0))#删去为计算方便使用的第一个顶点到自身的边
#排序后从大到小删去度大于2的边
treesort=sorted(tree,key=lambda S: S[1],reverse=True)#lambda是匿名函数,入口为S,返回S[1],将边按距离从大到小进行排序
print('Prim tree按边距从大到小排序treesort:',treesort)
finddu=dict()
for ((u, v), w) in treesort:#建立最小生成树各点度字典
if u not in finddu: