连通图所有生成树之中边权之和最小的生成树
使用邻接矩阵来存储图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Graph (): def __init__ (self,n:int ,maxNum = sys.maxsize,graphMatrix = [] ) -> None : if graphMatrix == []: self.graphMatrix = [[maxNum] * n for i in range (n)] else : self.graphMatrix = graphMatrix self.maxNum = maxNum self.size = n def add (self,a,b,weights ): self.graphMatrix[a][b] = weights def deleat (self,a,b ): self.graphMatrix[a][b] = self.maxNum
prim算法
从已知的点开始向外扩散,寻找最小的邻边,将顶点加入集合,已加入集合的点不能在加入,直到所有顶点加入到集合当中,构成最小生成树。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 graph LR 0 --2--- 1 0 --4--- 3 1 --1--- 3 3 --5--- 2 2 --4--- 4 3 --3--- 5 1 --2--- 2 4 --8--- 5 subgraph A 0 end subgraph B 1 2 3 4 5 end
从任意一个节点开始,将连通图划分为两个区域,一个是选中的,另一个是未选中的。每次选取选中的点当中连到未选中点的边权最小值,直到每个顶点被选中。
采用3个列表selected、minDist、parent,分别来记录:该节点是否被选中、当前节点连接顶点的边权最小值、将当前顶点连接到哪个顶点上。初始化为
.
0
1
2
3
4
5
selected
false
false
false
false
false
false
minDist
inf
inf
inf
inf
inf
inf
parent
-1
-1
-1
-1
-1
-1
接着将选中顶点的边权录入列表内
.
0
1
2
3
4
5
selected
true
false
false
false
false
false
minDist
inf
2
inf
4
inf
inf
parent
-1
0
-1
0
-1
-1
然后遍历minDis找出没选过点(即selected为false的点)最小的边(这里是1),将他加入集合内,用selected记录,更新minDist和parent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 graph LR 0 --2--- 1 0 --4--- 3 1 --1--- 3 3 --5--- 2 2 --4--- 4 3 --3--- 5 1 --2--- 2 4 --8--- 5 subgraph A 0 1 end subgraph B 2 3 4 5 end
选中的selected更新为true,minDist更新为inf(这步可以省略)
.
0
1
2
3
4
5
selected
true
true
false
false
false
false
minDist
inf
inf
inf
4
inf
inf
parent
-1
0
-1
0
-1
-1
在将刚刚加入的点的边进行更新,如果小于当前值且未加入集合就进行赋值
.
0
1
2
3
4
5
selected
true
true
false
false
false
false
minDist
inf
inf
2
1
inf
inf
parent
-1
0
1
1
-1
-1
重复更新选点的操作直到每个点被选中。
以下是完整代码
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 import sysclass Graph (): def __init__ (self,n:int ,maxNum = sys.maxsize,graphMatrix = [] ) -> None : if graphMatrix == []: self.graphMatrix = [[maxNum] * n for i in range (n)] else : self.graphMatrix = graphMatrix self.maxNum = maxNum self.size = n def add (self,a,b,weights ): self.graphMatrix[a][b] = weights def deleat (self,a,b ): self.graphMatrix[a][b] = self.maxNum def prim (self ): selected = [False ] * self.size minDist = [self.maxNum] * self.size parent = [-1 ] * self.size ans = 0 selected[0 ] = True for i in range (self.size): if self.graphMatrix[0 ][i] != self.maxNum: minDist[i] = self.graphMatrix[0 ][i] parent[i] = 0 for i in range (self.size): min = self.maxNum count = -1 for j in range (self.size): if min > minDist[j] and (not selected[j]): min = minDist[j] count = j if count != -1 : selected[count] = True ans += minDist[count] minDist[count] = self.maxNum for k in range (self.size): if self.graphMatrix[count][k] < minDist[k] and (not selected[k]): minDist[k] = self.graphMatrix[count][k] parent[k] = count return ans,parent
kruskal算法
与prim算法不同,kruskal算法则是由边出发,每次选取权值最小的边
将每个边加入到列表中,按权值排好序后由小到大遍历列表,如果边所连接的两个顶点未在同一个集合,就将两个集合合并,并选取该边,这里需要用到并查集。
1 2 3 4 5 6 7 8 9 10 11 graph LR subgraph A 0 --2--- 1 0 --4--- 3 1 --1--- 3 3 --5--- 2 2 --4--- 4 3 --3--- 5 1 --2--- 2 4 --8--- 5 end
列表:
权值
1
2
2
3
4
4
5
8
顶点1
4
0
1
3
0
2
3
4
顶点2
5
1
2
5
5
4
2
5
循环列表直到结束
完整代码
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 class DSU : def __init__ (self,size:int ): self.arr = list (range (size)) def __findHead (self,num:int ) -> int : if num == self.arr[num]: return num self.arr[num] = self.__findHead(self.arr[num]) return self.arr[num] def merge (self,a,b ) -> None : aHead = self.__findHead(a) bHead = self.__findHead(b) self.arr[aHead] = bHead def find (self,a,b ) -> bool : return self.__findHead(a) == self.__findHead(b) import sysclass Graph (): def __init__ (self,n:int ,maxNum = sys.maxsize,graphMatrix = [] ) -> None : if graphMatrix == []: self.graphMatrix = [[maxNum] * n for i in range (n)] else : self.graphMatrix = graphMatrix self.maxNum = maxNum self.size = n def add (self,a,b,weights ): self.graphMatrix[a][b] = weights def deleat (self,a,b ): self.graphMatrix[a][b] = self.maxNum def kruskal (self ): sideList = [] ans = 0 for i in range (self.size): for j in range (i): sideList.append([self.graphMatrix[i][j],i,j]) def returnSideMap (a ): return a[0 ] sideList.sort(key=returnSideMap) dsu = DSU(self.size) for side in sideList: if not dsu.find(side[1 ],side[2 ]): ans += side[0 ] dsu.merge(side[1 ],side[2 ]) return ans