题解 | #最小生成树#
最小生成树
https://www.nowcoder.com/practice/735a34ff4672498b95660f43b7fcd628
#Prim 算法和 Kruskal 算法是两种不同的最小生成树算法,它们的选择边的顺序以及生成最小生成树的过程不同,因此在某些情况下,它们得到的最小生成树结果可能不一样,在这里prim算法中部分算例不通过 # # #方法一,基于(克鲁斯卡尔)Kruskal算法,选择最小权重的边,利用并查集(并查集(Union Find):一种用于管理分组的数据结构 (一般使用树形结构来表示)Find:查询 a 元素和 b 元素是否为同一组Union:合并元素 a 和 b 为同一组 # class Graph: # #图,顶点数目,边的起止点,权重 # def __init__(self, vertices) -> None: # # 顶点数目 # self.v = vertices # self.graph = [] # def add_edge(self, src, dest, weight): # self.graph.append([src, dest, weight]) # # 递归,寻找i对应的根节点;递归终止条件按是找到根节点,即parent[i]==i # def find_set(self, parent, i): # if parent[i] == i: # return i # return self.find_set(parent, parent[i]) # # 合并集合(集合以根节点标识),比较 rank 并采用按秩合并的方式,是为了在并查集操作中保持较低的树高度,从而提高整体的性能和效率。 # def union(self, parent, rank, x, y): # x_root = self.find_set(parent, x) # y_root = self.find_set(parent, y) # if rank[x_root] < rank[y_root]: # parent[x_root] = y_root # elif rank[x_root] > rank[y_root]: # parent[y_root] = x_root # else: # parent[y_root] = x_root # rank[x_root] += 1 # def kruskal(self): # result = 0 # i = 0 # e = 0 # parent = [] # rank = [] # # lambda item: item[2] 是一个匿名函数(也称为 Lambda 函数),它接受一个参数 item,并返回 item 的第三个值(即 item[2])。这个 Lambda 函数在排序过程中被用作 key 参数传递给 sorted 函数 # self.graph = sorted(self.graph, key=lambda item: item[2]) # for node in range(self.v): # parent.append(node) # rank.append(0) # #print(rank, parent) # while e < self.v - 1: # src, dest, weight = self.graph[i] # i += 1 # #print(src, dest) # x = self.find_set(parent, src) # y = self.find_set(parent, dest) # if x != y: # e = e + 1 # result = result + weight # self.union(parent, rank, x, y) # return result # class Solution: # def miniSpanningTree(self, n, m, cost): # # write code here # g = Graph(n) # for i in range(m): # src, dest, weight = cost[i] # #索引从0,不妨取节点从0开始 # g.add_edge(src - 1, dest - 1, weight) # return g.kruskal() # #方法二,基于(普里姆)prim算法,用两个集合A{},B{}分别表示找到的点集,和未找到的点集;以A中的点为起点a,在B中找一个点为终点b,这两个点构成的边(a,b)的权值是其余边中最小的重复上述步骤#2,直至B中的点集为空,A中的点集为满 #Prim 算法通常会使用堆结构来优化查找最小成本边的过程。在每次查找最小边的时候,可以使用最小堆(min-heap)来维护当前连接到已访问村庄的边的集合,以便快速地找到最小成本的边。 # import heapq # class Graph(): # def __init__(self,vertices,) -> None: # self.v=vertices # #for _ in 中_表示一个无所谓的变量,作为占位符 # self.graph=[[0]*self.v for _ in range(int(self.v))] # def add_edge(self, src, dest, weight): # #无向图 # self.graph[src][dest] = weight # self.graph[dest][src] = weight # def Prim(self): # #初始父节点 # parent=[-1]*self.v # key=[float('inf')]*self.v # mst_set=[False]*self.v # heap=[] # key[0]=0 # heapq.heappush(heap,(0,0)) # while heap: # min_key,min_index=heapq.heappop(heap) # if min_key>key[min_index]: # continue # mst_set[min_index]=True # for i in range(self.v): # if ( # self.graph[min_index][i]!=0 # and not mst_set[i] # and self.graph[min_index][i]<key[i] # ): # parent[i]=min_index # key[i]=self.graph[min_index][i] # heapq.heappush(heap,(key[i],i)) # result=0 # for i in range(1,self.v): # result+=self.graph[i][parent[i]] # return result # class Solution: # def miniSpanningTree(self, n, m, cost): # # write code here # g = Graph(n) # for i in range(m): # src, dest, weight = cost[i] # #索引从0,不妨取节点从0开始 # g.add_edge(src-1 , dest-1 , weight) # return g.Prim() #方法三,不用heap结构的prim算法 class Graph(): def __init__(self,vertices,) -> None: self.v=vertices #for _ in 中_表示一个无所谓的变量,作为占位符 self.graph=[[0]*self.v for _ in range(int(self.v))] def add_edge(self, src, dest, weight): #无向图 self.graph[src][dest] = weight self.graph[dest][src] = weight def prim(self): mst_set = [False] * self.v key = [float('inf')] * self.v parent = [-1] * self.v key[0] = 0 for _ in range(self.v - 1): min_key = float('inf') u = -1 for v in range(self.v): if not mst_set[v] and key[v] < min_key: min_key = key[v] u = v mst_set[u] = True for v in range(self.v): if ( self.graph[u][v] > 0 and not mst_set[v] and self.graph[u][v] < key[v] ): key[v] = self.graph[u][v] parent[v] = u result = sum(key) return result class Solution: def miniSpanningTree(self, n, m, cost): # write code here g = Graph(n) for i in range(m): src, dest, weight = cost[i] #索引从0,不妨取节点从0开始 g.add_edge(src-1 , dest-1 , weight) return g.prim()