c++实现克鲁斯卡尔算法

时间: 2023-09-14 22:07:46 浏览: 21
克鲁斯卡尔算法是一种求解最小生成树的贪心算法,其基本思想是按照边的权值从小到大排序,依次选择权值最小且不构成环的边加入生成树中,直到生成树中有 n-1 条边为止。下面是 C++ 实现克鲁斯卡尔算法的示例代码: ```c++ #include <iostream> #include <algorithm> using namespace std; const int MAXN = 1000; // 最大顶点数 const int MAXM = 10000; // 最大边数 int n, m; // 顶点数和边数 int fa[MAXN]; // 并查集数组 struct edge { int u, v, w; // 边的起点、终点和权值 } e[MAXM]; // 存储边的数组 bool cmp(edge a, edge b) { // 排序函数,按边权升序排序 return a.w < b.w; } int find(int x) { // 并查集查找函数 return fa[x] == x ? x : fa[x] = find(fa[x]); } int kruskal() { // 克鲁斯卡尔算法函数 int ans = 0, cnt = 0; for (int i = 1; i <= n; ++i) fa[i] = i; // 初始化并查集 sort(e + 1, e + m + 1, cmp); // 对边按权值升序排序 for (int i = 1; i <= m; ++i) { // 枚举所有边 int u = find(e[i].u), v = find(e[i].v); if (u != v) { // 如果不在同一个连通块中 fa[u] = v; // 合并连通块 ans += e[i].w; // 计算最小生成树的权值 ++cnt; if (cnt == n - 1) break; // 边数达到最大值,退出循环 } } return ans; } int main() { cin >> n >> m; for (int i = 1; i <= m; ++i) { cin >> e[i].u >> e[i].v >> e[i].w; } int ans = kruskal(); cout << ans << endl; return 0; } ``` 在该程序中,使用结构体 `edge` 存储边的起点、终点和权值,使用并查集维护连通块,使用排序函数 `cmp` 将边按权值升序排序,使用函数 `kruskal` 实现克鲁斯卡尔算法,并返回最小生成树的权值。在主函数中,输入顶点数和边数,读入边的信息,调用函数 `kruskal`,输出最小生成树的权值。

相关推荐

以下是克鲁斯卡尔算法的C语言代码实现: #include <stdio.h> #include <stdlib.h> #define MAX_VERTEX_NUM 100 // 最大顶点数 #define MAX_EDGE_NUM 100 // 最大边数 typedef char VertexType; // 顶点类型 typedef int EdgeType; // 权值类型 typedef struct { VertexType vertexes[MAX_VERTEX_NUM]; // 顶点集合 EdgeType edges[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 边集合 int vertex_num; // 顶点数 int edge_num; // 边数 } Graph; typedef struct { int begin; // 起点 int end; // 终点 EdgeType weight; // 权值 } Edge; int find(int *parent, int f) { while (parent[f] > 0) { f = parent[f]; } return f; } void kruskal(Graph *g) { Edge edges[MAX_EDGE_NUM]; int parent[MAX_VERTEX_NUM] = {0}; // 初始化边集合 int k = 0; for (int i = 0; i < g->vertex_num; i++) { for (int j = i + 1; j < g->vertex_num; j++) { if (g->edges[i][j] != 0) { edges[k].begin = i; edges[k].end = j; edges[k].weight = g->edges[i][j]; k++; } } } // 按权值升序排序 for (int i = 0; i < g->edge_num - 1; i++) { for (int j = i + 1; j < g->edge_num; j++) { if (edges[i].weight > edges[j].weight) { Edge tmp = edges[i]; edges[i] = edges[j]; edges[j] = tmp; } } } // 初始化parent数组 for (int i = 0; i < g->vertex_num; i++) { parent[i] = 0; } // 遍历边集合 printf("Kruskal Algorithm:\n"); for (int i = 0; i < g->edge_num; i++) { int begin = edges[i].begin; int end = edges[i].end; int weight = edges[i].weight; int root1 = find(parent, begin); int root2 = find(parent, end); if (root1 != root2) { parent[root1] = root2; printf("(%c, %c) %d\n", g->vertexes[begin], g->vertexes[end], weight); } } } int main() { Graph g = { {'A', 'B', 'C', 'D', 'E', 'F', 'G'}, { {0, 12, 0, 0, 0, 16, 14}, {12, 0, 10, 0, 0, 7, 0}, {0, 10, 0, 3, 5, 6, 0}, {0, 0, 3, 0, 4, 0, 0}, {0, 0, 5, 4, 0, 2, 8}, {16, 7, 6, 0, 2, 0, 9}, {14, 0, 0, 0, 8, 9, 0}, }, 7, 12 }; kruskal(&g); return 0; } 这里我们采用邻接矩阵的方式存储图,并实现了一个find函数来查找某个节点的根节点。kruskal函数中首先初始化了边集合,然后按照权值升序排序。接着初始化parent数组,然后遍历边集合,对于每一条边,我们分别找到它两个节点的根节点,如果根节点不同,说明这两个节点不在同一个连通分量中,我们将它们合并,并输出这条边。最终输出的就是最小生成树的边集合。
克鲁斯卡尔算法是一种求解最小生成树的贪心算法,其基本思想是将所有边按照权值从小到大排序,然后依次加入到生成树中,如果加入一条边会形成环,则不加入这条边,直到生成树中包含所有的点为止。 下面是克鲁斯卡尔算法的 C 语言实现: c #include <stdio.h> #include <stdlib.h> #define MAX_N 1000 #define MAX_M 10000 typedef struct { int u, v, w; } Edge; Edge edges[MAX_M]; int fa[MAX_N]; int cmp(const void *a, const void *b) { return ((Edge *) a)->w - ((Edge *) b)->w; } int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); } int main() { int n, m; scanf("%d%d", &n, &m); for (int i = 0; i < m; ++i) { scanf("%d%d%d", &edges[i].u, &edges[i].v, &edges[i].w); } qsort(edges, m, sizeof(Edge), cmp); for (int i = 1; i <= n; ++i) { fa[i] = i; } int ans = 0, cnt = 0; for (int i = 0; i < m; ++i) { int u = edges[i].u, v = edges[i].v, w = edges[i].w; int fu = find(u), fv = find(v); if (fu != fv) { fa[fu] = fv; ans += w; ++cnt; if (cnt == n - 1) break; } } printf("%d\n", ans); return 0; } 首先定义了一个 Edge 结构体,用来表示边,其中 u 和 v 表示边的两个端点,w 表示边的权值。接下来定义了一个 cmp 函数,用来对边按照权值从小到大排序。然后定义了一个 find 函数,用来查找某个点所在的集合。fa 数组用来记录每个点所在的集合的根节点。 在 main 函数中,首先读入点数和边数,然后读入每条边的信息,并将所有边按照权值从小到大排序。接着初始化每个点所在的集合,然后依次将每条边加入生成树中,如果加入一条边会形成环,则不加入这条边,直到生成树中包含所有的点为止。最后输出生成树的权值和即可。
好的,下面是用C++实现克鲁斯卡尔算法求最小树的程序: cpp #include <iostream> #include <algorithm> #include <vector> using namespace std; // 定义边的结构体 struct Edge { int from, to, weight; Edge(int u, int v, int w) : from(u), to(v), weight(w) {} }; // 定义并查集 class UnionFind { public: UnionFind(int n) { count = n; parent.resize(n); for (int i = 0; i < n; ++i) { parent[i] = i; } } int find(int x) { while (x != parent[x]) { parent[x] = parent[parent[x]]; x = parent[x]; } return x; } void unite(int x, int y) { int rootX = find(x); int rootY = find(y); if (rootX == rootY) return; parent[rootX] = rootY; --count; } int getCount() const { return count; } private: int count; vector<int> parent; }; // 定义比较函数,用于将边按权值从小到大排序 bool cmp(const Edge& e1, const Edge& e2) { return e1.weight < e2.weight; } vector<Edge> kruskal(int n, vector<Edge>& edges) { vector<Edge> result; UnionFind uf(n); sort(edges.begin(), edges.end(), cmp); for (const auto& edge : edges) { if (uf.getCount() == 1) break; int u = edge.from; int v = edge.to; if (uf.find(u) == uf.find(v)) continue; uf.unite(u, v); result.push_back(edge); } return result; } int main() { int n, m; cin >> n >> m; vector<Edge> edges; for (int i = 0; i < m; ++i) { int u, v, w; cin >> u >> v >> w; edges.emplace_back(u, v, w); } vector<Edge> result = kruskal(n, edges); for (const auto& edge : result) { cout << edge.from << " " << edge.to << " " << edge.weight << endl; } return 0; } 程序输入格式为: n m u1 v1 w1 u2 v2 w2 ... um vm wm 其中 n 表示节点个数,m 表示边的个数,后面 m 行每行表示一条边,每条边包含三个整数,分别表示起点、终点和权值。 程序输出最小树的边集,每行输出一条边,格式为: from to weight 其中 from 和 to 表示边的起点和终点,weight 表示边的权值。 希望能够帮到你!
下面是克鲁斯卡尔最小生成树算法的C++代码示例: cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; // 边的结构体 struct Edge { int src, dest, weight; }; // 并查集的结构体 struct Subset { int parent, rank; }; // 比较函数,用于按边的权重进行排序 bool compare(Edge a, Edge b) { return a.weight < b.weight; } // 查找操作,寻找元素所属集合的根节点 int find(vector<Subset>& subsets, int i) { if (subsets[i].parent != i) { subsets[i].parent = find(subsets, subsets[i].parent); } return subsets[i].parent; } // 合并操作,将两个集合进行合并 void unionSet(vector<Subset>& subsets, int x, int y) { int xroot = find(subsets, x); int yroot = find(subsets, y); if (subsets[xroot].rank < subsets[yroot].rank) { subsets[xroot].parent = yroot; } else if (subsets[xroot].rank > subsets[yroot].rank) { subsets[yroot].parent = xroot; } else { subsets[yroot].parent = xroot; subsets[xroot].rank++; } } // 克鲁斯卡尔最小生成树算法 void kruskalMST(vector<Edge>& edges, int V) { vector<Edge> result; // 存储最小生成树的边 // 按照边的权重进行排序 sort(edges.begin(), edges.end(), compare); vector<Subset> subsets(V); for (int i = 0; i < V; i++) { subsets[i].parent = i; subsets[i].rank = 0; } int e = 0; // 用于控制结果数组的下标 int i = 0; // 用于控制排序后的边数组的下标 while (e < V - 1 && i < edges.size()) { Edge nextEdge = edges[i++]; int x = find(subsets, nextEdge.src); int y = find(subsets, nextEdge.dest); if (x != y) { result.push_back(nextEdge); unionSet(subsets, x, y); e++; } } // 输出最小生成树的边及其权重 cout << "最小生成树的边:" << endl; for (int i = 0; i < result.size(); i++) { cout << result[i].src << " - " << result[i].dest << ",权重:" << result[i].weight << endl; } } int main() { int V, E; cout << "请输入顶点数:"; cin >> V; cout << "请输入边数:"; cin >> E; vector<Edge> edges(E); for (int i = 0; i < E; i++) { cout << "请输入第 " << i + 1 << " 条边的起点、终点和权重:"; cin >> edges[i].src >> edges[i].dest >> edges[i].weight; } kruskalMST(edges, V); return 0; } 这段代码实现了克鲁斯卡尔最小生成树算法,通过输入顶点数和边数,然后逐条输入边的起点、终点和权重,最后输出最小生成树的边及其权重。注意,该代码中使用了并查集来判断是否形成环路,并使用了排序算法进行边的排序。
以下是使用Prim算法求解无向图的最小生成树的C++代码: c++ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int MAXN=1e3+10; const int INF=0x3f3f3f3f; int n,m,ans; int vis[MAXN],dis[MAXN]; int g[MAXN][MAXN]; void prim() { memset(vis,0,sizeof(vis)); memset(dis,INF,sizeof(dis)); for(int i=1;i<=n;i++) dis[i]=g[1][i]; vis[1]=1;ans=0; for(int i=1;i<n;i++) { int pos,minn=INF; for(int j=1;j<=n;j++) if(!vis[j]&&dis[j]<minn) minn=dis[j],pos=j; vis[pos]=1;ans+=dis[pos]; for(int j=1;j<=n;j++) if(!vis[j]) dis[j]=min(dis[j],g[pos][j]); } } int main() { while(~scanf("%d%d",&n,&m)) { memset(g,INF,sizeof(g)); for(int i=1;i<=m;i++) { int u,v,c; scanf("%d%d%d",&u,&v,&c); g[u][v]=g[v][u]=c; } prim(); printf("%d\n",ans); } return 0; } 以下是使用Kruskal算法求解无向图的最小生成树的C++代码: c++ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int MAXN=1e3+10; const int INF=0x3f3f3f3f; int n,m,ans; int fa[MAXN]; struct edge { int u,v,c; bool operator < (const edge& e) const { return c<e.c; } }e[MAXN*MAXN]; int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } void kruskal() { sort(e+1,e+m+1); int cnt=0; for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++) { int u=e[i].u,v=e[i].v,c=e[i].c; int x=find(u),y=find(v); if(x!=y) { fa[x]=y;ans+=c; cnt++; if(cnt==n-1) break; } } } int main() { while(~scanf("%d%d",&n,&m)) { memset(fa,0,sizeof(fa)); memset(e,0,sizeof(e)); for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].c); kruskal(); printf("%d\n",ans); } return 0; }
以下是使用邻接矩阵实现图的算法和测试代码: c++ #include <iostream> #include <cstring> using namespace std; const int MAXN = 100; const int INF = 0x3f3f3f3f; int n; // 图中顶点数 int G[MAXN][MAXN]; // 邻接矩阵 // 普里姆算法生成最小生成树 void prim(int s) { int d[MAXN]; // 存储当前各个顶点到最小生成树的最短距离 bool vis[MAXN] = {false}; // 标记顶点是否已经在最小生成树中 memset(d, INF, sizeof(d)); // 初始化距离为无穷大 d[s] = 0; // 起点到自己的距离为0 for (int i = 0; i < n; i++) { int u = -1, min_d = INF; // 找到距离最小的顶点 for (int j = 0; j < n; j++) { if (!vis[j] && d[j] < min_d) { u = j; min_d = d[j]; } } if (u == -1) return; // 找不到可连接的顶点 vis[u] = true; // 将顶点加入最小生成树 for (int v = 0; v < n; v++) { if (!vis[v] && G[u][v] < d[v]) { d[v] = G[u][v]; // 更新最短距离 } } } } // 克鲁斯卡尔算法生成最小生成树 struct edge { int u, v, w; // 边的起点、终点和权值 bool operator<(const edge& E) const { return w < E.w; // 按照权值从小到大排序 } } edges[MAXN * MAXN]; // 存储所有边 int fa[MAXN]; // 并查集 int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } void kruskal() { int cnt = 0; // 记录加入最小生成树的边数 for (int i = 0; i < n; i++) fa[i] = i; // 初始化并查集 sort(edges, edges + n * (n - 1) / 2); // 将边按照权值排序 for (int i = 0; i < n * (n - 1) / 2; i++) { int u = edges[i].u, v = edges[i].v, w = edges[i].w; int fu = find(u), fv = find(v); if (fu != fv) { // 如果不在同一个连通块中 fa[fu] = fv; // 合并连通块 cnt++; // 边数+1 if (cnt == n - 1) break; // 边数达到n-1,生成树完成 } } } // Dijkstra算法求单源最短路径 void dijkstra(int s, int d[]) { bool vis[MAXN] = {false}; // 标记顶点是否已经确定最短路径 memset(d, INF, sizeof(d)); // 初始化距离为无穷大 d[s] = 0; // 起点到自己的距离为0 for (int i = 0; i < n; i++) { int u = -1, min_d = INF; // 找到距离最小的顶点 for (int j = 0; j < n; j++) { if (!vis[j] && d[j] < min_d) { u = j; min_d = d[j]; } } if (u == -1) return; // 找不到可连接的顶点 vis[u] = true; // 将顶点加入最短路径 for (int v = 0; v < n; v++) { if (!vis[v] && G[u][v] != INF && d[u] + G[u][v] < d[v]) { d[v] = d[u] + G[u][v]; // 更新最短距离 } } } } int main() { cin >> n; memset(G, INF, sizeof(G)); // 初始化邻接矩阵为无穷大 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { int w; cin >> w; if (w != -1) G[i][j] = w; // 如果有边,存储边的权值 } } // 测试普里姆算法 prim(0); // 测试克鲁斯卡尔算法 kruskal(); // 测试Dijkstra算法 int s; cin >> s; int d[MAXN]; dijkstra(s, d); // 输出最小生成树和最短路径 cout << "最小生成树:" << endl; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (G[i][j] != INF && find(i) == find(j)) { cout << i << " " << j << " " << G[i][j] << endl; } } } cout << "最短路径:" << endl; for (int i = 0; i < n; i++) { if (i == s) continue; cout << s << " " << i << " " << d[i] << endl; } return 0; }
以下是使用C++实现Prim算法和Kruskal算法求解带权连通图的最小生成树的程序: c++ #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 1001; const int INF = 0x3f3f3f3f; struct Edge{ int u, v, w; }edge[MAXN*MAXN/2]; int n, m; // n为节点数,m为边数 int G[MAXN][MAXN]; // 邻接矩阵存图 int d[MAXN], vis[MAXN]; // d数组记录节点到生成树的最短距离,vis数组记录节点是否已加入生成树 int pre[MAXN]; // 记录每个节点在生成树中的前驱节点 // Prim算法 void Prim(int s){ memset(d, INF, sizeof(d)); // 初始化d数组 memset(vis, 0, sizeof(vis)); // 初始化vis数组 d[s] = 0; // 节点s到生成树的最短距离为0 for(int i=0; i<n; i++){ int u = -1; // u表示当前离生成树最近的节点 for(int j=0; j<n; j++){ if(!vis[j] && (u==-1 || d[j]<d[u])){ u = j; } } vis[u] = true; for(int v=0; v<n; v++){ if(!vis[v] && d[v]>G[u][v]){ d[v] = G[u][v]; pre[v] = u; } } } } // Kruskal算法 int fa[MAXN]; // 并查集数组 bool cmp(Edge a, Edge b){ return a.w < b.w; } int find(int x){ if(fa[x] == x) return x; return fa[x] = find(fa[x]); } void Kruskal(){ sort(edge, edge+m, cmp); // 将边按权值从小到大排序 for(int i=0; i<n; i++) fa[i] = i; // 初始化并查集数组 for(int i=0; i<m; i++){ int u = edge[i].u, v = edge[i].v, w = edge[i].w; int x = find(u), y = find(v); if(x != y){ // 如果不在同一个集合中,则加入生成树 pre[v] = u; fa[x] = y; } } } int main(){ cin >> n >> m; // 输入节点数和边数 memset(G, INF, sizeof(G)); // 初始化邻接矩阵为INF for(int i=0; i<m; i++){ int u, v, w; cin >> u >> v >> w; G[u][v] = G[v][u] = w; // 无向图 edge[i].u = u; edge[i].v = v; edge[i].w = w; } // Prim算法求解最小生成树 Prim(0); cout << "Prim Algorithm:\n"; for(int i=1; i<n; i++){ cout << pre[i] << " -> " << i << " : " << d[i] << "\n"; } // Kruskal算法求解最小生成树 Kruskal(); cout << "Kruskal Algorithm:\n"; for(int i=1; i<n; i++){ cout << pre[i] << " -> " << i << " : " << G[pre[i]][i] << "\n"; } return 0; } 程序中的Prim算法和Kruskal算法都使用了前驱节点数组pre来记录生成树的构造过程,输出最小生成树的边时只需按照pre数组输出即可。

最新推荐

最短路径选择算法(prim kruscal)

最短路径选择算法,包括prim普利姆 kruscal克鲁斯卡尔 C++实现 绝对能用

工资透视表.xls

工资透视表.xls

固定资产移转表.xlsx

固定资产移转表.xlsx

软件工程期末复习资料(二仙桥某校定制版)

软件工程期末复习资料(二仙桥某校定制版)

基于 token 的多平台身份认证架构设计.docx

站在更高的维度做架构,来自一线互联网大厂的经验总结,少走弯路少踩坑,值得拥有。

基于51单片机的usb键盘设计与实现(1).doc

基于51单片机的usb键盘设计与实现(1).doc

"海洋环境知识提取与表示:专用导航应用体系结构建模"

对海洋环境知识提取和表示的贡献引用此版本:迪厄多娜·察查。对海洋环境知识提取和表示的贡献:提出了一个专门用于导航应用的体系结构。建模和模拟。西布列塔尼大学-布雷斯特,2014年。法语。NNT:2014BRES0118。电话:02148222HAL ID:电话:02148222https://theses.hal.science/tel-02148222提交日期:2019年HAL是一个多学科的开放存取档案馆,用于存放和传播科学研究论文,无论它们是否被公开。论文可以来自法国或国外的教学和研究机构,也可以来自公共或私人研究中心。L’archive ouverte pluridisciplinaire论文/西布列塔尼大学由布列塔尼欧洲大学盖章要获得标题西布列塔尼大学博士(博士)专业:计算机科学海洋科学博士学院对海洋环境知识的提取和表示的贡献体系结构的建议专用于应用程序导航。提交人迪厄多内·察察在联合研究单位编制(EA编号3634)海军学院

react中antd组件库里有个 rangepicker 我需要默认显示的当前月1号到最后一号的数据 要求选择不同月的时候 开始时间为一号 结束时间为选定的那个月的最后一号

你可以使用 RangePicker 的 defaultValue 属性来设置默认值。具体来说,你可以使用 moment.js 库来获取当前月份和最后一天的日期,然后将它们设置为 RangePicker 的 defaultValue。当用户选择不同的月份时,你可以在 onChange 回调中获取用户选择的月份,然后使用 moment.js 计算出该月份的第一天和最后一天,更新 RangePicker 的 value 属性。 以下是示例代码: ```jsx import { useState } from 'react'; import { DatePicker } from 'antd';

基于plc的楼宇恒压供水系统学位论文.doc

基于plc的楼宇恒压供水系统学位论文.doc

"用于对齐和识别的3D模型计算机视觉与模式识别"

表示用于对齐和识别的3D模型马蒂厄·奥布里引用此版本:马蒂厄·奥布里表示用于对齐和识别的3D模型计算机视觉与模式识别[cs.CV].巴黎高等师范学校,2015年。英语NNT:2015ENSU0006。电话:01160300v2HAL Id:tel-01160300https://theses.hal.science/tel-01160300v22018年4月11日提交HAL是一个多学科的开放获取档案馆,用于存放和传播科学研究文件,无论它们是否已这些文件可能来自法国或国外的教学和研究机构,或来自公共或私人研究中心。L’archive ouverte pluridisciplinaire博士之路博士之路博士之路在获得等级时,DOCTEURDE L'ÉCOLE NORMALE SUPERIEURE博士学校ED 386:巴黎中心数学科学Discipline ou spécialité:InformatiquePrésentée et soutenue par:马蒂厄·奥布里le8 may 2015滴度表示用于对齐和识别的Unité derechercheThèse dirigée par陪审团成员équipe WILLOW(CNRS/ENS/INRIA UMR 8548)慕尼黑工业大学(TU Munich�