full file
This commit is contained in:
commit
25653141cb
55
gpt/complex.md
Normal file
55
gpt/complex.md
Normal file
@ -0,0 +1,55 @@
|
||||
### **Prim算法**
|
||||
|
||||
#### **时间复杂度**
|
||||
Prim算法的时间复杂度取决于图的存储方式和优先队列的使用:
|
||||
|
||||
1. **邻接矩阵表示**:
|
||||
- 每次选择最小权值的边需要遍历所有顶点,时间复杂度为 \( O(V^2) \)。
|
||||
- 适合**稠密图**(边较多时,通常 \( E \approx V^2 \))。
|
||||
|
||||
2. **邻接表表示 + 最小堆**:
|
||||
- 初始化堆时,将所有边加入堆的时间复杂度为 \( O(V \log V) \)。
|
||||
- 在堆中插入或删除边的操作为 \( O(\log V) \),遍历所有边需要 \( O(E \log V) \)。
|
||||
- 总复杂度为 \( O(E \log V) \),适合**稀疏图**(边较少时,通常 \( E \ll V^2 \))。
|
||||
|
||||
#### **空间复杂度**
|
||||
- **邻接矩阵表示**:\( O(V^2) \) 用于存储所有顶点间的权值信息。
|
||||
- **邻接表表示 + 最小堆**:
|
||||
- 邻接表占用 \( O(V + E) \)。
|
||||
- 优先队列(最小堆)需要 \( O(V) \) 的空间。
|
||||
- 总空间复杂度为 \( O(V + E) \)。
|
||||
|
||||
---
|
||||
|
||||
### **Kruskal算法**
|
||||
|
||||
#### **时间复杂度**
|
||||
Kruskal算法的时间复杂度主要由以下部分组成:
|
||||
|
||||
1. **边排序**:
|
||||
- 使用快速排序或堆排序对 \( E \) 条边排序,时间复杂度为 \( O(E \log E) \)。
|
||||
2. **并查集操作**:
|
||||
- 查找和合并操作的时间复杂度为 \( O(\alpha(V)) \)(近似常数),每条边最多进行一次,整体为 \( O(E \cdot \alpha(V)) \)。
|
||||
- 其中 \( \alpha(V) \) 是反Ackermann函数,增长极慢,可认为是一个很小的常数。
|
||||
|
||||
总时间复杂度:
|
||||
- \( O(E \log E + E \cdot \alpha(V)) \)。
|
||||
- 由于 \( E \log E \geq E \cdot \alpha(V) \),最终复杂度可以简化为 \( O(E \log E) \)。
|
||||
|
||||
#### **空间复杂度**
|
||||
- 用于存储所有边的列表:\( O(E) \)。
|
||||
- 并查集数组(parent 和 rank):\( O(V) \)。
|
||||
- 总空间复杂度为 \( O(E + V) \)。
|
||||
|
||||
---
|
||||
|
||||
### **时间和空间复杂度对比**
|
||||
|
||||
| **算法** | **时间复杂度** | **空间复杂度** | **适用场景** |
|
||||
|-----------------|------------------------------|-------------------------|---------------------------|
|
||||
| **Prim 算法** | \( O(V^2) \) 或 \( O(E \log V) \) | \( O(V^2) \) 或 \( O(V + E) \) | 稠密图/稀疏图 |
|
||||
| **Kruskal 算法**| \( O(E \log E) \) | \( O(E + V) \) | 较稀疏的图 |
|
||||
|
||||
**总结**:
|
||||
- **稠密图**(\( E \approx V^2 \)):Prim 算法使用邻接矩阵效果更好。
|
||||
- **稀疏图**(\( E \ll V^2 \)):Kruskal 算法效率更高,且更易实现。
|
49
gpt/conception.md
Normal file
49
gpt/conception.md
Normal file
@ -0,0 +1,49 @@
|
||||
### **算法基本思想**
|
||||
|
||||
#### **Prim 算法**
|
||||
Prim 算法是一种贪心策略构建最小生成树的方法。
|
||||
- **核心思想**:
|
||||
从任意一个顶点开始,逐步将权值最小的边加入生成树,同时保证生成树不会形成环。
|
||||
|
||||
- **步骤**:
|
||||
1. 初始化一个集合 `MST`,用于存储已包含在生成树中的顶点。
|
||||
2. 从起始顶点出发,将所有与之相连的边放入一个优先队列(最小堆)。
|
||||
3. 每次从优先队列中取出权值最小的边,若该边的目标顶点不在 `MST` 中,则将该顶点加入 `MST`,并将与该顶点相连的边加入优先队列。
|
||||
4. 重复此过程,直到所有顶点都包含在生成树中。
|
||||
|
||||
- **时间复杂度**:
|
||||
- 使用邻接矩阵:\( O(V^2) \)
|
||||
适用于稠密图。
|
||||
- 使用邻接表+最小堆:\( O(E \log V) \)
|
||||
适用于稀疏图,其中 \( V \) 是顶点数,\( E \) 是边数。
|
||||
|
||||
---
|
||||
|
||||
#### **Kruskal 算法**
|
||||
Kruskal 算法是一种基于边的贪心策略构建最小生成树的方法。
|
||||
- **核心思想**:
|
||||
按照权值从小到大排序所有边,然后逐步选取不形成环的边,直到构建出最小生成树。
|
||||
|
||||
- **步骤**:
|
||||
1. 将所有边按照权值从小到大排序。
|
||||
2. 初始化一个并查集,用于判断两个顶点是否属于同一连通分量。
|
||||
3. 从权值最小的边开始,依次检查该边是否会形成环:
|
||||
- 如果不会形成环(即边的两个顶点不在同一集合中),将该边加入生成树,并合并两个顶点所属的集合。
|
||||
- 否则,跳过该边。
|
||||
4. 重复此过程,直到生成树包含 \( V-1 \) 条边。
|
||||
|
||||
- **时间复杂度**:
|
||||
- 边排序:\( O(E \log E) \),因为需要对所有边进行排序。
|
||||
- 并查集操作:近似 \( O(E \log V) \),其中查找和合并操作效率很高(接近常数时间)。
|
||||
- 总时间复杂度:\( O(E \log E + E \log V) \)。由于 \( E \log E \geq E \log V \),可以简化为 \( O(E \log E) \)。
|
||||
|
||||
---
|
||||
|
||||
### **算法比较**
|
||||
|
||||
| **算法** | **适用场景** | **时间复杂度** | **特点** |
|
||||
|-----------------|-------------------------------|-------------------------|--------------------------------------------------------------------------|
|
||||
| **Prim 算法** | 稠密图,适合用邻接矩阵 | \( O(V^2) \) 或 \( O(E \log V) \) | 基于顶点,逐步扩展生成树;实现相对简单,适合稠密图时直接用邻接矩阵表示。 |
|
||||
| **Kruskal 算法**| 稀疏图,适合用边列表 | \( O(E \log E) \) | 基于边,灵活性更高;需要先排序所有边,适合稀疏图。 |
|
||||
|
||||
两种算法在不同场景下都可用,但通常 **Prim 更适合稠密图,Kruskal 更适合稀疏图**。
|
145
gpt/explain.md
Normal file
145
gpt/explain.md
Normal file
@ -0,0 +1,145 @@
|
||||
好的,下面是对修正后的 **Prim 算法** 实现代码的逐行解析:
|
||||
|
||||
### 代码
|
||||
|
||||
```python
|
||||
import heapq
|
||||
```
|
||||
- 引入 `heapq` 库来使用优先队列(最小堆),该库提供了堆的基本操作,如插入元素和取出最小值。
|
||||
|
||||
```python
|
||||
class Graph:
|
||||
def __init__(self, vertices):
|
||||
self.V = vertices # 顶点数
|
||||
self.graph = [] # 存储边的列表
|
||||
```
|
||||
- **`Graph` 类**:表示图的结构,构造函数 `__init__` 初始化图,接收顶点数量 `vertices` 作为参数。
|
||||
- `self.V`:存储图的顶点数。
|
||||
- `self.graph`:一个空列表,用来存储图的所有边。
|
||||
|
||||
```python
|
||||
def add_edge(self, u, v, weight):
|
||||
self.graph.append([u, v, weight])
|
||||
```
|
||||
- **`add_edge` 方法**:向图中添加一条边。每条边由起点 `u`、终点 `v` 和边的权重 `weight` 构成,并存储为一个三元组 `[u, v, weight]`。
|
||||
|
||||
```python
|
||||
def prim_mst(self):
|
||||
mst_set = [False] * self.V # 记录是否已加入 MST
|
||||
edge_heap = [(0, 0, -1)] # (权值, 顶点, 父节点) (-1 表示起始节点无父节点)
|
||||
total_cost = 0
|
||||
mst_edges = []
|
||||
```
|
||||
- **`prim_mst` 方法**:实现 Prim 算法,计算图的最小生成树(MST)。
|
||||
- `mst_set`:一个布尔列表,初始化为 `False`,用于记录每个顶点是否已经加入到生成树中。
|
||||
- `edge_heap`:一个最小堆,用于存储候选的边,每个元素是一个三元组 `(权值, 顶点, 父节点)`。初始时,将起点 `0` 的权值设为 `0`,父节点为 `-1`。
|
||||
- `total_cost`:记录生成树的总权重。
|
||||
- `mst_edges`:用于存储最小生成树的边。
|
||||
|
||||
```python
|
||||
while edge_heap and len(mst_edges) < self.V - 1:
|
||||
weight, u, parent = heapq.heappop(edge_heap)
|
||||
if mst_set[u]: # 忽略已在 MST 中的节点
|
||||
continue
|
||||
```
|
||||
- **`while edge_heap and len(mst_edges) < self.V - 1`**:循环直到最小生成树包含 `V-1` 条边,或者没有更多的边可供选择。
|
||||
- `heapq.heappop(edge_heap)`:从最小堆中取出权值最小的边(`weight, u, parent`)。
|
||||
- `if mst_set[u]`: 如果当前顶点 `u` 已经在最小生成树中,跳过这个顶点。
|
||||
|
||||
```python
|
||||
mst_set[u] = True
|
||||
total_cost += weight
|
||||
```
|
||||
- `mst_set[u] = True`:将顶点 `u` 标记为已加入最小生成树。
|
||||
- `total_cost += weight`:将当前边的权重 `weight` 加到 `total_cost` 上。
|
||||
|
||||
```python
|
||||
if parent != -1:
|
||||
mst_edges.append((parent, u, weight))
|
||||
```
|
||||
- `if parent != -1`:只有在顶点 `u` 的父节点不为 `-1` 时,才将该边添加到 `mst_edges` 中。起始节点 `0` 的父节点为 `-1`,不会记录为边。
|
||||
|
||||
```python
|
||||
for v, w in self._adjacent_edges(u):
|
||||
if not mst_set[v]:
|
||||
heapq.heappush(edge_heap, (w, v, u))
|
||||
```
|
||||
- **`_adjacent_edges` 方法**(稍后分析)返回与顶点 `u` 相连的所有边。
|
||||
- 遍历与 `u` 相邻的所有顶点 `v` 和边的权重 `w`,如果 `v` 尚未加入最小生成树 (`mst_set[v] == False`),则将边 `(w, v, u)` 添加到优先队列中。
|
||||
|
||||
```python
|
||||
return total_cost, mst_edges
|
||||
```
|
||||
- 返回最小生成树的总权重 `total_cost` 和所有的生成树边 `mst_edges`。
|
||||
|
||||
```python
|
||||
def _adjacent_edges(self, u):
|
||||
# 返回与顶点 u 相连的所有边
|
||||
return [(v, weight) for (u_, v, weight) in self.graph if u_ == u] + \
|
||||
[(u, weight) for (u, v_, weight) in self.graph if v_ == u]
|
||||
```
|
||||
- **`_adjacent_edges` 方法**:返回所有与顶点 `u` 相连的边。由于图是无向图,因此需要分别查找以 `u` 为起点的边和以 `u` 为终点的边。
|
||||
|
||||
```python
|
||||
def kruskal_mst(self):
|
||||
self.graph.sort(key=lambda x: x[2]) # 按权值排序
|
||||
parent = list(range(self.V))
|
||||
rank = [0] * self.V
|
||||
```
|
||||
- **`kruskal_mst` 方法**:实现 Kruskal 算法,计算图的最小生成树。
|
||||
- `self.graph.sort(key=lambda x: x[2])`:首先按边的权重对图中的所有边进行排序。
|
||||
- `parent`:初始化每个顶点的父节点为自身(使用并查集结构)。
|
||||
- `rank`:用于优化并查集的秩(深度)信息,避免树的高度过高。
|
||||
|
||||
```python
|
||||
def find(u):
|
||||
if parent[u] != u:
|
||||
parent[u] = find(parent[u])
|
||||
return parent[u]
|
||||
```
|
||||
- **`find` 函数**:实现并查集中的查找操作,查找顶点 `u` 的根节点,并通过路径压缩优化查找过程。
|
||||
|
||||
```python
|
||||
def union(u, v):
|
||||
root_u = find(u)
|
||||
root_v = find(v)
|
||||
if rank[root_u] > rank[root_v]:
|
||||
parent[root_v] = root_u
|
||||
elif rank[root_u] < rank[root_v]:
|
||||
parent[root_u] = root_v
|
||||
else:
|
||||
parent[root_v] = root_u
|
||||
rank[root_u] += 1
|
||||
```
|
||||
- **`union` 函数**:实现并查集中的合并操作,将两个集合合并为一个集合。
|
||||
- 根据秩优化合并操作,将较小的树合并到较大的树下面,保持树的平衡。
|
||||
|
||||
```python
|
||||
mst_edges = []
|
||||
total_cost = 0
|
||||
```
|
||||
- 初始化最小生成树的边列表 `mst_edges` 和总权重 `total_cost`。
|
||||
|
||||
```python
|
||||
for u, v, weight in self.graph:
|
||||
if find(u) != find(v):
|
||||
union(u, v)
|
||||
mst_edges.append((u, v, weight))
|
||||
total_cost += weight
|
||||
```
|
||||
- 遍历所有的边,对于每一条边,如果边的两个端点属于不同的集合(即不在同一连通分量中),就将这条边加入最小生成树。
|
||||
- 使用 `find(u) != find(v)` 判断是否属于不同的集合,若是,则合并它们。
|
||||
- 将边 `(u, v, weight)` 加入到 `mst_edges` 中,并累加权重 `weight` 到 `total_cost`。
|
||||
|
||||
```python
|
||||
return total_cost, mst_edges
|
||||
```
|
||||
- 返回 Kruskal 算法的总权重 `total_cost` 和生成树的边 `mst_edges`。
|
||||
|
||||
---
|
||||
|
||||
### **总结**
|
||||
- **Prim 算法**:通过最小堆逐步选择连接最小生成树的边,最终得到最小生成树。
|
||||
- **Kruskal 算法**:通过边的权值排序和并查集来逐步选择最小的边,最终得到最小生成树。
|
||||
|
||||
两种算法的核心思想不同,但最终目标相同,都是求出图的最小生成树。
|
158
gpt/main.md
Normal file
158
gpt/main.md
Normal file
@ -0,0 +1,158 @@
|
||||
以下是实验报告框架和 Python 实现的模板,供参考:
|
||||
|
||||
---
|
||||
|
||||
### 实验报告:最小生成树
|
||||
|
||||
#### 学号:XXXXXX
|
||||
#### 姓名:XXXXXX
|
||||
|
||||
---
|
||||
|
||||
#### **一、最小生成树基本思想**
|
||||
|
||||
最小生成树(Minimum Spanning Tree, MST)是一个无向连通图的一个子图,满足以下条件:
|
||||
1. 是连通图;
|
||||
2. 包含图中所有顶点,但只包含 \( n-1 \) 条边(其中 \( n \) 为顶点数);
|
||||
3. 所有边的权值之和最小。
|
||||
|
||||
常用的算法包括:
|
||||
- **Prim算法**:逐步扩展生成树,通过选择权值最小的边加入生成树。
|
||||
- **Kruskal算法**:先按权值对边排序,再通过判断是否形成环来选择边加入生成树。
|
||||
|
||||
---
|
||||
|
||||
#### **二、源码**
|
||||
以下代码实现了 Prim 和 Kruskal 两种算法:
|
||||
|
||||
```python
|
||||
import heapq
|
||||
|
||||
# 图的表示方式
|
||||
class Graph:
|
||||
def __init__(self, vertices):
|
||||
self.V = vertices # 顶点数
|
||||
self.graph = [] # 存储边的列表
|
||||
|
||||
def add_edge(self, u, v, weight):
|
||||
self.graph.append([u, v, weight])
|
||||
|
||||
# Prim 算法
|
||||
def prim_mst(self):
|
||||
mst_set = [False] * self.V
|
||||
edge_heap = [(0, 0)] # (权值, 顶点)
|
||||
total_cost = 0
|
||||
mst_edges = []
|
||||
|
||||
while edge_heap:
|
||||
weight, u = heapq.heappop(edge_heap)
|
||||
if mst_set[u]:
|
||||
continue
|
||||
mst_set[u] = True
|
||||
total_cost += weight
|
||||
for v, w in self._adjacent_edges(u):
|
||||
if not mst_set[v]:
|
||||
heapq.heappush(edge_heap, (w, v))
|
||||
mst_edges.append((u, v, w))
|
||||
|
||||
return total_cost, mst_edges
|
||||
|
||||
def _adjacent_edges(self, u):
|
||||
return [(v, weight) for (u_, v, weight) in self.graph if u_ == u] + \
|
||||
[(u, weight) for (u, v_, weight) in self.graph if v_ == u]
|
||||
|
||||
# Kruskal 算法
|
||||
def kruskal_mst(self):
|
||||
self.graph.sort(key=lambda x: x[2]) # 按权值排序
|
||||
parent = list(range(self.V))
|
||||
rank = [0] * self.V
|
||||
|
||||
def find(u):
|
||||
if parent[u] != u:
|
||||
parent[u] = find(parent[u])
|
||||
return parent[u]
|
||||
|
||||
def union(u, v):
|
||||
root_u = find(u)
|
||||
root_v = find(v)
|
||||
if rank[root_u] > rank[root_v]:
|
||||
parent[root_v] = root_u
|
||||
elif rank[root_u] < rank[root_v]:
|
||||
parent[root_u] = root_v
|
||||
else:
|
||||
parent[root_v] = root_u
|
||||
rank[root_u] += 1
|
||||
|
||||
mst_edges = []
|
||||
total_cost = 0
|
||||
|
||||
for u, v, weight in self.graph:
|
||||
if find(u) != find(v):
|
||||
union(u, v)
|
||||
mst_edges.append((u, v, weight))
|
||||
total_cost += weight
|
||||
|
||||
return total_cost, mst_edges
|
||||
|
||||
|
||||
# 测试代码
|
||||
if __name__ == "__main__":
|
||||
g = Graph(5) # 创建一个包含5个顶点的图
|
||||
g.add_edge(0, 1, 2)
|
||||
g.add_edge(0, 3, 6)
|
||||
g.add_edge(1, 3, 8)
|
||||
g.add_edge(1, 2, 3)
|
||||
g.add_edge(1, 4, 5)
|
||||
g.add_edge(2, 4, 7)
|
||||
g.add_edge(3, 4, 9)
|
||||
|
||||
print("Prim 算法结果:")
|
||||
cost, edges = g.prim_mst()
|
||||
print(f"总权值: {cost}, 边: {edges}")
|
||||
|
||||
print("\nKruskal 算法结果:")
|
||||
cost, edges = g.kruskal_mst()
|
||||
print(f"总权值: {cost}, 边: {edges}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### **三、算法分析**
|
||||
|
||||
1. **Prim算法**
|
||||
- **时间复杂度**:\( O(V^2) \)(邻接矩阵实现)或 \( O(E \log V) \)(邻接表+堆实现)
|
||||
- **空间复杂度**:\( O(V + E) \)
|
||||
|
||||
2. **Kruskal算法**
|
||||
- **时间复杂度**:\( O(E \log E + E \log V) \),主要来源于边排序和并查集操作。
|
||||
- **空间复杂度**:\( O(E + V) \)
|
||||
|
||||
---
|
||||
|
||||
#### **四、实验运行结果图**
|
||||
运行代码后,终端输出示例如下:
|
||||
|
||||
```
|
||||
Prim 算法结果:
|
||||
总权值: 16, 边: [(0, 1, 2), (1, 2, 3), (1, 4, 5), (0, 3, 6)]
|
||||
|
||||
Kruskal 算法结果:
|
||||
总权值: 16, 边: [(0, 1, 2), (1, 2, 3), (1, 4, 5), (0, 3, 6)]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### **五、实验提交方式**
|
||||
|
||||
- 文件夹结构:
|
||||
```
|
||||
学号+姓名/
|
||||
├── 实验报告.docx
|
||||
└── mst.py
|
||||
```
|
||||
- 上传至指定云盘路径:`上电云盘/课程目录/20241216文件夹/`
|
||||
- 提交时间:课前15分钟,逾期无效。
|
||||
|
||||
---
|
||||
|
||||
如需修改或补充,请告诉我!
|
20
main.py
Normal file
20
main.py
Normal file
@ -0,0 +1,20 @@
|
||||
# 测试代码
|
||||
from mst import Graph
|
||||
|
||||
if __name__ == "__main__":
|
||||
g = Graph(5) # 创建一个包含5个顶点的图
|
||||
g.add_edge(0, 1, 2)
|
||||
g.add_edge(0, 3, 6)
|
||||
g.add_edge(1, 3, 8)
|
||||
g.add_edge(1, 2, 3)
|
||||
g.add_edge(1, 4, 5)
|
||||
g.add_edge(2, 4, 7)
|
||||
g.add_edge(3, 4, 9)
|
||||
|
||||
print("Prim 算法结果:")
|
||||
cost, edges = g.prim_mst()
|
||||
print(f"总权值: {cost}, 边: {edges}")
|
||||
|
||||
print("\nKruskal 算法结果:")
|
||||
cost, edges = g.kruskal_mst()
|
||||
print(f"总权值: {cost}, 边: {edges}")
|
74
mst.py
Normal file
74
mst.py
Normal file
@ -0,0 +1,74 @@
|
||||
import heapq
|
||||
|
||||
# 图的表示方式
|
||||
class Graph:
|
||||
def __init__(self, vertices):
|
||||
self.V = vertices # 顶点数
|
||||
self.graph = [] # 存储边的列表
|
||||
|
||||
def add_edge(self, u, v, weight):
|
||||
self.graph.append([u, v, weight])
|
||||
|
||||
# Prim 算法
|
||||
def prim_mst(self):
|
||||
mst_set = [False] * self.V # 记录是否已加入 MST
|
||||
edge_heap = [(0, 0, -1)] # (权值, 顶点, 父节点) (-1 表示起始节点无父节点)
|
||||
total_cost = 0
|
||||
mst_edges = []
|
||||
|
||||
while edge_heap and len(mst_edges) < self.V - 1:
|
||||
weight, u, parent = heapq.heappop(edge_heap)
|
||||
if mst_set[u]: # 忽略已在 MST 中的节点
|
||||
continue
|
||||
|
||||
mst_set[u] = True
|
||||
total_cost += weight
|
||||
|
||||
# 将加入的边存储(跳过起始节点的 -1 父节点)
|
||||
if parent != -1:
|
||||
mst_edges.append((parent, u, weight))
|
||||
|
||||
# 将相邻边加入优先队列
|
||||
for v, w in self._adjacent_edges(u):
|
||||
if not mst_set[v]:
|
||||
heapq.heappush(edge_heap, (w, v, u))
|
||||
|
||||
return total_cost, mst_edges
|
||||
|
||||
def _adjacent_edges(self, u):
|
||||
# 返回与顶点 u 相连的所有边
|
||||
return [(v, weight) for (u_, v, weight) in self.graph if u_ == u] + \
|
||||
[(u, weight) for (u, v_, weight) in self.graph if v_ == u]
|
||||
|
||||
# Kruskal 算法
|
||||
def kruskal_mst(self):
|
||||
self.graph.sort(key=lambda x: x[2]) # 按权值排序
|
||||
parent = list(range(self.V))
|
||||
rank = [0] * self.V
|
||||
|
||||
def find(u):
|
||||
if parent[u] != u:
|
||||
parent[u] = find(parent[u])
|
||||
return parent[u]
|
||||
|
||||
def union(u, v):
|
||||
root_u = find(u)
|
||||
root_v = find(v)
|
||||
if rank[root_u] > rank[root_v]:
|
||||
parent[root_v] = root_u
|
||||
elif rank[root_u] < rank[root_v]:
|
||||
parent[root_u] = root_v
|
||||
else:
|
||||
parent[root_v] = root_u
|
||||
rank[root_u] += 1
|
||||
|
||||
mst_edges = []
|
||||
total_cost = 0
|
||||
|
||||
for u, v, weight in self.graph:
|
||||
if find(u) != find(v):
|
||||
union(u, v)
|
||||
mst_edges.append((u, v, weight))
|
||||
total_cost += weight
|
||||
|
||||
return total_cost, mst_edges
|
Loading…
Reference in New Issue
Block a user