最小生成树完整代码,包含各边权值,以及边和顶点信息

最小生成树(Minimum Spanning Tree, MST)

最小生成树是指在一个 连通无向带权图 中,找到一棵生成树,使得所有边的权值之和最小。常见的算法有:

  1. Prim 算法(适合稠密图,时间复杂度 O(V^2) 或 O(E log V)

  2. Kruskal 算法(适合稀疏图,时间复杂度 O(E log V)

这里我们使用 Kruskal 算法,因为它更容易实现,并且适用于大多数情况。


Kruskal 算法步骤

  1. 对所有边按权值从小到大排序

  2. 初始化并查集(Union-Find),用于检测是否形成环。

  3. 遍历所有边

    • 如果当前边的两个端点不在同一个集合(不形成环),则加入 MST,并合并这两个集合。

    • 否则跳过(避免环)。

  4. 直到选取 V-1 条边(生成树的边数)。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 并查集(Union-Find)实现
class UnionFind {
private:
    vector<int> parent, rank;
public:
    UnionFind(int n) {
        parent.resize(n);
        rank.resize(n, 0);
        for (int i = 0; i < n; ++i) {
            parent[i] = i; // 初始时每个节点的父节点是自己
        }
    }

    // 查找根节点(路径压缩)
    int find(int u) {
        if (parent[u] != u) {
            parent[u] = find(parent[u]); // 路径压缩优化
        }
        return parent[u];
    }

    // 合并两个集合(按秩合并)
    void unite(int u, int v) {
        int rootU = find(u);
        int rootV = find(v);
        if (rootU == rootV) return; // 已经在同一个集合

        // 按秩合并(小树合并到大树)
        if (rank[rootU] > rank[rootV]) {
            parent[rootV] = rootU;
        } else if (rank[rootU] < rank[rootV]) {
            parent[rootU] = rootV;
        } else {
            parent[rootV] = rootU;
            rank[rootU]++;
        }
    }
};

// 边的结构体
struct Edge {
    int u, v, weight;
    Edge(int u, int v, int weight) : u(u), v(v), weight(weight) {}

    // 用于排序(按权值升序)
    bool operator<(const Edge& other) const {
        return weight < other.weight;
    }
};

// Kruskal 算法
vector<Edge> kruskalMST(vector<Edge>& edges, int V) {
    sort(edges.begin(), edges.end()); // 按权值排序
    UnionFind uf(V); // 初始化并查集
    vector<Edge> mst; // 存储 MST 的边

    for (const Edge& edge : edges) {
        if (uf.find(edge.u) != uf.find(edge.v)) { // 不形成环
            mst.push_back(edge); // 加入 MST
            uf.unite(edge.u, edge.v); // 合并集合
            if (mst.size() == V - 1) break; // 已经选了 V-1 条边
        }
    }

    return mst;
}

int main() {
    int V, E;
    cout << "输入顶点数和边数: ";
    cin >> V >> E;

    vector<Edge> edges;
    cout << "输入每条边 (u v weight):" << endl;
    for (int i = 0; i < E; ++i) {
        int u, v, weight;
        cin >> u >> v >> weight;
        edges.emplace_back(u, v, weight);
    }

    vector<Edge> mst = kruskalMST(edges, V);

    cout << "最小生成树的边:" << endl;
    int totalWeight = 0;
    for (const Edge& edge : mst) {
        cout << edge.u << " - " << edge.v << " : " << edge.weight << endl;
        totalWeight += edge.weight;
    }
    cout << "总权值: " << totalWeight << endl;

    return 0;
}

代码讲解

1. 并查集(Union-Find)

用于高效检测环:

  • find(u):查找 u 的根节点(带路径压缩优化)。

  • unite(u, v):合并 u 和 v 所在集合(按秩合并)。

2. 边的结构体 Edge

存储边的信息:

  • uv:边的两个端点。

  • weight:边的权值。

  • 重载 < 运算符,用于排序。

3. Kruskal 算法核心

  1. 排序所有边(从小到大)。

  2. 遍历所有边

    • 如果 u 和 v 不在同一个集合(find(u) != find(v)),则加入 MST。

    • 合并 u 和 v 的集合(unite(u, v))。

  3. 直到选出 V-1 条边(生成树的边数)。

4. 主函数

  • 输入顶点数 V 和边数 E

  • 输入所有边,调用 kruskalMST 计算最小生成树。

  • 输出 MST 的边及总权值。


示例运行

输入

复制

下载

输入顶点数和边数: 4 5
输入每条边 (u v weight):
0 1 10
0 2 6
0 3 5
1 3 15
2 3 4

输出

复制

下载

最小生成树的边:
2 - 3 : 4
0 - 3 : 5
0 - 1 : 10
总权值: 19

总结

算法适用场景时间复杂度空间复杂度
Kruskal稀疏图O(E log V)O(V + E)
Prim稠密图O(V^2) 或 O(E log V)O(V)

Kruskal 算法适合大多数情况,代码简洁,容易理解。

解释 vector<Edge> kruskalMST(vector<Edge>& edges, int V) 的返回值类型

1. vector<Edge> 是什么?
  • vector<Edge> 是 C++ 中的 动态数组(vector),存储的元素类型是 Edge(即我们定义的边结构体)。

  • 它类似于 int[] 或 string[],但可以动态调整大小(不需要提前指定长度)。

2. kruskalMST 函数的作用
  • 输入

    • edges:存储所有边的 vector<Edge>(按权值排序后)。

    • V:图的顶点数量(用于判断何时停止选边)。

  • 输出

    • 返回 vector<Edge>,存储的是 最小生成树(MST)的所有边

3. 为什么返回 vector<Edge>
  • Kruskal 算法的结果是 一组边(构成最小生成树)。

  • 我们需要返回这些边,以便后续计算总权值或输出具体路径。

  • 例如:

    cpp

    复制

    下载

    vector<Edge> mst = kruskalMST(edges, V); // 接收返回的 MST 边集
4. 类比理解
  • 假设有一个函数 vector<int> getNumbers(),它返回一组整数:

    cpp

    复制

    下载

    vector<int> numbers = getNumbers(); // 接收返回的整数列表
  • 同理,kruskalMST 返回的是 边的列表,而不是单个值。

5. 代码中的实际应用

在 main 函数中:

cpp

复制

下载

vector<Edge> mst = kruskalMST(edges, V); // 接收 MST 的边
for (const Edge& edge : mst) {
    cout << edge.u << " - " << edge.v << " : " << edge.weight << endl;
}
  • mst 是一个 vector<Edge>,存储了所有属于最小生成树的边。

  • 通过遍历 mst,可以输出每条边的信息。


总结

部分含义
vector<Edge>返回值类型,表示一个动态数组,存储 Edge 结构体
kruskalMST函数名,用于计算最小生成树
edges输入参数,存储所有边的列表
V输入参数,图的顶点数量
返回值最小生成树的所有边(vector<Edge> 类型)

这种设计使得我们可以 灵活地处理返回的边集,例如:

  • 计算总权值。

  • 输出具体的生成树结构。

  • 进一步分析图的连通性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值