158 lines
4.1 KiB
Markdown
158 lines
4.1 KiB
Markdown
|
以下是实验报告框架和 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分钟,逾期无效。
|
|||
|
|
|||
|
---
|
|||
|
|
|||
|
如需修改或补充,请告诉我!
|