本文共 3615 字,大约阅读时间需要 12 分钟。
最小生成树(Minimum Spanning Tree, MST)是图中连接所有顶点并不包含环路的最低权重的树。生成树需要满足以下两个条件:
最小生成树的构造方法主要有Kruskal算法和Prim算法两种,以下将分别介绍这两种算法的实现过程和注意事项。
Kruskal算法的主要思想是通过不断添加不形成回路的边,来构造最小生成树。该算法的具体步骤如下:
1. 初始化
2. 遍历边
3. 处理特殊情况
并查集(Union-Find)的作用
Kruskal算法的优点
实现代码示例
#include#include #include #include #include using namespace std;struct edge { int u, v, w;};// 并查集初始化bool findParent(int x, int parent[]) { if (parent[x] != x) { parent[x] = findParent(parent[x], parent); } return parent[x];}void kruskal(vector parent, vector & res, vector > adj) { sort(adj.begin(), adj.end(), [](const edge& a, const edge& b) { return a.w < b.w; }); res.resize(adj.size() + 1); for (int i = 1; i <= adj.size(); ++i) res[i] = -1; for (int i = 1; i <= adj.size(); ++i) { int u = adj[i].u, v = adj[i].v; int pu = findParent(u, parent), pv = findParent(v, parent); if (pu != pv) { // 合并两个不同的连通分量 if (res[pu] == -1 && res[pv] == -1) { res[pu] = adj[i].w; res[pv] = adj[i].w; } else if (res[pu] == -1) { res[pu] = adj[i].w; } else { res[pv] = max(res[pv], res[pu] + adj[i].w); } parent[pu] = pv; ++cnt; } } // 计算最小生成树的权重总和 int sum = 0; for (int i = 1; i <= n; ++i) { if (res[i] != -1) { sum += res[i]; } } return sum;}int main() { // 输入处理 // ... cout << (sum <= c ? "Yes" : "No") << endl; return 0;}
Prim算法的思路是从一个起始点出发,逐步扩展最小生成树的集合。具体步骤如下:
1. 初始化
dist[]
,记录每个顶点到已加的最小生成树的距离初始值均为较大的数(如INF
)。vis[]
,用于记录已经加入的顶点。0
),并初始化该点的距离和访问标记。2. 引入边
3. 更新距离
u
后,更新所有未访问的顶点到u
的最小距离。过程描述
vis[]
中只有起始点被标记,距离数组中只有起始点距离为0。t
。t
连接到最近的已访问点v
。t
已经纳入生成树,更新生成树的总权重。t
为已访问,并更新所有顶点到t
的最短距离。注意事项
Prim算法的优点
实现代码示例
#include#include #include #include using namespace std;int main() { // 初始化输入结构 const int INF = 1e9; vector > adj; // 无向图的边列表 int n, m, c; // 输入顶点数、边数、目标权重 // 输入边数据并构建邻接矩阵 while (cin >> c >> n >> m) { memset(adj, INF, sizeof(adj)); for (int i = 0; i < m; ++i) { int u, v, w; cin >> u >> v >> w; adj[u-1][v-1] = min(w, adj[u-1][v-1]); adj[v-1][u-1] = min(w, adj[v-1][u-1]); } } vector dist(n, INF), vis(n, 0), res; // 起始点设为0 vis[0] = 1; dist[0] = 0; res = 0; for (int i = 0; i < n; ++i) { if (i == 0) res = dist[i]: else if (vis[i]) continue; int t = -1; for (int j = 0; j < n; ++j) { if (!vis[j] && (t == -1 || dist[t] > dist[j])) { t = j; } } if (t == -1) break; if (i == 0) { res += dist[t]; vis[t] = 1; for (int j = 0; j < n; ++j) { dist[j] = min(dist[j], dist[t] + adj[t][j]); } } else { res += min(res, dist[t] + (i - 1 ? min(dist[u], dist[v]) : 0)); // 类似逻辑需要根据具体实现细化 } vis[t] = 1; for (int j = 0; j < n; ++j) { dist[j] = min(dist[j], dist[t] + adj[t][j]); } } if (res > c) { cout << "No" << endl; } else { cout << "Yes" << endl; } return 0;}
总结
转载地址:http://ivphz.baihongyu.com/