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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
| ''' 用最小的代价连接图所有的点
图的最小生成树 Minimum Spanning Tree
树 : 无回路 v个顶点v-1条边 生成树: 包含了全部顶点 v-1条边都在图里 最小生成树: 边的权重和是最小的 向生成树加任意一条边都会构成回路 ''' ''' 此题 贪心算法 "贪": 每一步都要最"好"的。 "好": 权重最小的边。
约束条件 只能用图里有的边 只能正好用掉v-1条边 不能有回路
''' ''' Prim贪心算法 ---- 让一颗小树长大 类似Dijkstra算法,但是不是在原有基础上累加,而是只考虑一步长度。
# dist[w] 定义为w结点到整个树的距离,parent[s] = -1 ,初始结点的dist定义为 +∞。
def Prim(): MST = {s} while 1: v = MST未收录的dist最小者 if 这样的v不存在: break 收录v点 for v的所有邻接点w: if w未被收录: if E(v,w) < dist[w]: dist[w] = E(v,w) parent[s] = v if MST收录到的v的数量 < v个: return '存在孤立的点,生成树不存在。 '
# 时间复杂度 T = O(v**2)
# 所以适应稠密图(稠密 E > v)(稀疏 E ≈ v)
''' ''' Kruskal 贪心算法 ---- 将森林合并成树 默认为每个结点就是一棵树 每次收进一条边,就等于两棵树并成了一棵树, 最后把所有的结点并进来成为一棵树。
def Kruskal(): MST = {} # 最小生成树存的是边。 while ( MST 中不到v-1条边 and E 中还有边 ): 从E中取出一条权重最小的边 E(v,w) # *** 最小堆 *** 将 E(v,w) 从 E 中删除 if E(v,w) 不在MST 中构成回路: # *** 并查集 *** 如果新加入的点w不在 v的集合内,那就不会形成闭合回路。 将 E(v,w)加入 新的集合 else: 无视E(v,w)。 if MST 中不到 v-1 条边: return '存在不联通点,生成树不存在。'
# 时间复杂度 T = O(Elog(E))
# 适用于稀疏图。
''' ''' (v1) 2 (v2) 4 1 3 10 (v3) 2 (v4) 7 (v5) 5 8 4 6 (v6) 1 (v7)
'''
class Graph(): def __init__(self,n_vertices): self._n_vertices = n_vertices self.G = [ [float('inf') for _ in range(n_vertices) ] for _ in range(n_vertices) ] def add_edge(self,v,w,weight): self.G[v][w] = weight self.G[w][v] = weight def show_Graph(self): for i in range(self._n_vertices): print(self.G[i]) graph = Graph(7) graph.add_edge(0,1,2) graph.add_edge(0,3,1) graph.add_edge(1,3,3) graph.add_edge(1,4,10) graph.add_edge(2,0,4) graph.add_edge(2,5,5) graph.add_edge(3,2,2) graph.add_edge(3,4,7) graph.add_edge(3,5,8) graph.add_edge(3,6,4) graph.add_edge(4,6,6) graph.add_edge(6,5,1) graph.show_Graph() print(' \n')
class data(): def __init__(self,Vertex_num): self.dist = [float('inf') for _ in range(Vertex_num)] self.parent = [-1 for _ in range(Vertex_num)]
def Prim(s,data): while 1: v = Find_Smallest_Dist(s,data) if v == None: break data.dist[v] = 0 for w in near_Node(v): if data.dist[w] != 0: weight_v_w = graph.G[v][w] if data.dist[w] > weight_v_w: data.dist[w] = weight_v_w data.parent[w] = v for collected in data.dist: if collected != 0: return '这样的最小生成树不存在,因为有孤立点。' return data
def Find_Smallest_Dist(s,data): if data.dist[s] != 0: data.dist[s] = -1 uncollected_list = [i for i in range(len(data.dist)) if data.dist[i]!=0] print(uncollected_list,'没收集到!!!') if uncollected_list == []: return None for i in uncollected_list: if data.dist[i] == min([data.dist[i] for i in uncollected_list]): print(i,' 没收集的最小dist对应位置') print(data.dist[i],' 没有收录的最小dist值') return i
def near_Node(v): near_Node = [ w for w in range(len(graph.G[v])) if w != float('inf')] return near_Node
def CreatTree(H): G = [[] for _ in range(7)] for i in range(len(H)): for j in range(len(H )): if H[j] == i: G[i].append({j:graph.G[i][j]}) for i in range(len(G)): if G[i] != []: print(i,G[i]) return G
data = data(7) Prim(0,data) print('\n\n**********\n Prim算法的结果如下:') print('dist',data.dist) print('parent',data.parent)
t = CreatTree(data.parent) print('**********\n')
class Graph(): def __init__(self,n_vertices): self._n_vertices = n_vertices self.G = [[] for _ in range(self._n_vertices)] def add_edge(self,pro_vertices,new_vertices,edge_weight): self.G[pro_vertices].append({new_vertices:edge_weight}) self.G[new_vertices].append({pro_vertices: edge_weight}) def show_Graph(self): for i in range(self._n_vertices): print(self.G[i]) graph = Graph(7) graph.add_edge(0,1,2) graph.add_edge(0,3,1) graph.add_edge(1,3,3) graph.add_edge(1,4,10) graph.add_edge(2,0,4) graph.add_edge(2,5,5) graph.add_edge(3,2,2) graph.add_edge(3,4,7) graph.add_edge(3,5,8) graph.add_edge(3,6,4) graph.add_edge(4,6,6) graph.add_edge(6,5,1) graph.show_Graph() Edge = [ [0,1,2], [0,3,1], [1,3,3], [1,4,10], [2,0,4], [2,5,5], [3,2,2], [3,4,7], [3,5,8], [3,6,4], [4,6,6], [6,5,1] ] print(Edge) print('_________\n')
def Kruskal(): E = [] new_MST = [-1 for _ in range(len(graph.G))] MST = Edge H = creat_Heap(MST) while ( Edge_Num(new_MST)<len(graph.G)-1 and len(MST) ): theMin = pop_smallest_Edge(H,MST) v = theMin[0] w = theMin[1] weight = theMin[2] print(new_MST) print(theMin) if NotInTheSomeSet(v,w,new_MST): Unin(v,w,new_MST) E.append(theMin) print(v,w) count = 0 for i in new_MST: if i == -1: count += 1 if count > 1: return '存在不联通点,生成树不存在。%d个集合'%count return E
def Edge_Num(new_MST): count = 0 for i in new_MST: if i != -1: count += 1 return count
def findRoot(x,new_MST): if new_MST[x] == -1: return x else: new_MST[x] = findRoot(new_MST[x],new_MST) return new_MST[x]
def NotInTheSomeSet(v,w,new_MST): if findRoot(v,new_MST) != findRoot(w,new_MST): return True
def Unin(v,w,new_MST): v_root = findRoot(v,new_MST) w_root = findRoot(w,new_MST) for i in range(len(new_MST)): if new_MST[i] == w_root: new_MST[i] = v_root new_MST[w_root] = v_root
def creat_Heap(MST): H = HeapStruct() H.MinHeapCreate(Capacity_Size=20) for e in MST: H.Insert(e) return H
def pop_smallest_Edge(heap,MST): theMin = heap.DeleteMin() for e in MST: if e == theMin: MST.remove(e) return theMin
class HeapStruct(): def __init__(self,elements=[None],addre=0,capacity=0): self.elements = elements self.addre = addre self.capacity = capacity def MinHeapCreate(self,Capacity_Size): print(' 若插入数值,请确保插入数值在 0 以上 。结点容量为%d'%Capacity_Size) self.elements = [None] * (Capacity_Size+1) self.capacity = Capacity_Size self.elements[0] = self.MinData() print('self capacity = %s'%self.capacity) def MinData(self): return [0,0,0] def Insert(self,item): if self.IsFull(): print('最小堆已满') return i = self.addre + 1 if self.elements[0][2] >= item[2]: print('插入数值大小小于下限') return while self.elements[i//2][2] > item[2]: print(self.elements[i//2],item) self.elements[i] = self.elements[i//2] i //= 2 self.elements[i] = item self.addre += 1 def IsFull(self): if self.addre == self.capacity: print( self.addre,self.capacity) return 1 return 0 def IsEmpty(self): if self.addre == 0: return 1 return def DeleteMin(self): if self.IsEmpty(): print('最小堆已空。') return minitem = self.elements[1] temp = self.elements[self.addre] self.elements[self.addre] = None self.addre -= 1 parent = 1 while parent*2 <= self.addre: left_child = parent * 2 if self.addre != left_child and self.elements[left_child+1][2] < self.elements[left_child][2]: child = left_child + 1 else: child = left_child if self.elements[child][2] <= temp[2]: self.elements[parent] = self.elements[child] parent = child elif self.elements[child][2] > temp[2]: self.elements[parent] = temp return minitem self.elements[parent] = temp return minitem
E = Kruskal() print('\n\n**********\n Kruskal算法的结果如下:') print('最终的最小生成树为:') for edge in E: print(edge)
|