请通过C++使用prim算法和kruskal算法编程实现最小生成树

时间: 2023-06-20 18:06:44 浏览: 29
以下是C++实现Prim算法和Kruskal算法求最小生成树的示例代码: Prim算法: ```c++ #include <iostream> #include <vector> #include <queue> #include <cstring> using namespace std; const int MAXN = 1005; const int INF = 0x3f3f3f3f; int n; int g[MAXN][MAXN]; int d[MAXN]; bool vis[MAXN]; void prim(int s) { memset(d, INF, sizeof(d)); memset(vis, false, sizeof(vis)); d[s] = 0; priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq; pq.push(make_pair(d[s], s)); while (!pq.empty()) { int u = pq.top().second; pq.pop(); if (vis[u]) continue; vis[u] = true; for (int v = 1; v <= n; v++) { if (g[u][v] < INF && !vis[v] && g[u][v] < d[v]) { d[v] = g[u][v]; pq.push(make_pair(d[v], v)); } } } } int main() { int m; cin >> n >> m; memset(g, INF, sizeof(g)); for (int i = 1; i <= m; i++) { int u, v, w; cin >> u >> v >> w; g[u][v] = g[v][u] = w; } prim(1); int ans = 0; for (int i = 1; i <= n; i++) { if (d[i] == INF) { cout << "No solution!" << endl; return 0; } ans += d[i]; } cout << ans << endl; return 0; } ``` Kruskal算法: ```c++ #include <iostream> #include <algorithm> #include <vector> using namespace std; const int MAXN = 1005; int n; int fa[MAXN]; struct Edge { int u, v, w; bool operator<(const Edge& e) const { return w < e.w; } } edges[MAXN * MAXN]; int find(int x) { if (x == fa[x]) return x; return fa[x] = find(fa[x]); } int kruskal() { int ans = 0, cnt = 0; sort(edges, edges + n * (n - 1) / 2); for (int i = 1; i <= n; i++) fa[i] = i; 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; ans += w; cnt++; if (cnt == n - 1) break; } } return ans; } int main() { int m; cin >> n >> m; for (int i = 0; i < m; i++) { int u, v, w; cin >> u >> v >> w; edges[i] = { u, v, w }; } cout << kruskal() << endl; return 0; } ```

相关推荐

Prim算法和Kruskal算法都是求解最小生成树的经典算法之一,这里我们分别介绍如何使用无向网的邻接矩阵存储结构实现这两个算法。 ## Prim算法 Prim算法是一种贪心算法,它从一个源节点开始不断扩展最小生成树的边,直到所有节点都被包含在最小生成树中。具体实现步骤如下: 1. 初始化最小生成树的边集为空集,将源节点加入最小生成树中。 2. 对于不在最小生成树中的节点,计算它们与最小生成树中节点的连边的权值,选择权值最小的边加入最小生成树中。 3. 重复步骤2,直到所有节点都被包含在最小生成树中。 下面是使用C++实现Prim算法的代码: cpp #include <iostream> #include <vector> #include <climits> using namespace std; const int MAXN = 100; // 最大节点数 const int INF = INT_MAX; // 无穷大 int graph[MAXN][MAXN]; // 无向网的邻接矩阵 bool visited[MAXN]; // 节点是否被访问过 int dist[MAXN]; // 节点到最小生成树的距离 int parent[MAXN]; // 最小生成树中节点的父节点 void prim(int start, int n) { // 初始化 for (int i = 0; i < n; i++) { visited[i] = false; dist[i] = INF; parent[i] = -1; } dist[start] = 0; // 按照Prim算法,不断扩展最小生成树 for (int i = 0; i < n; i++) { // 找到距离最小的节点 int minDist = INF, minIndex = -1; for (int j = 0; j < n; j++) { if (!visited[j] && dist[j] < minDist) { minDist = dist[j]; minIndex = j; } } // 将节点加入最小生成树中 visited[minIndex] = true; for (int j = 0; j < n; j++) { if (!visited[j] && graph[minIndex][j] < dist[j]) { dist[j] = graph[minIndex][j]; parent[j] = minIndex; } } } } int main() { int n = 6; // 节点数 // 初始化邻接矩阵 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { graph[i][j] = INF; } } graph[0][1] = graph[1][0] = 6; graph[0][2] = graph[2][0] = 1; graph[0][3] = graph[3][0] = 5; graph[1][2] = graph[2][1] = 5; graph[1][4] = graph[4][1] = 3; graph[2][3] = graph[3][2] = 5; graph[2][4] = graph[4][2] = 6; graph[2][5] = graph[5][2] = 4; graph[3][5] = graph[5][3] = 2; graph[4][5] = graph[5][4] = 6; prim(0, n); int sum = 0; for (int i = 0; i < n; i++) { if (parent[i] != -1) { cout << parent[i] << "-" << i << " " << graph[parent[i]][i] << endl; sum += graph[parent[i]][i]; } } cout << "Weight of MST: " << sum << endl; return 0; } ## Kruskal算法 Kruskal算法也是一种贪心算法,它从所有边中选择权值最小的边,依次加入最小生成树中,直到所有节点都被包含在最小生成树中。具体实现步骤如下: 1. 初始化最小生成树的边集为空集。 2. 将所有边按照权值从小到大排序。 3. 依次选择每条边,如果它的两个端点不在同一个连通分量中,则将它加入最小生成树中,否则跳过。 4. 重复步骤3,直到所有节点都被包含在最小生成树中。 下面是使用C++实现Kruskal算法的代码: cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; const int MAXN = 100; // 最大节点数 const int INF = INT_MAX; // 无穷大 struct Edge { int from, to, weight; bool operator<(const Edge& other) const { return weight < other.weight; } }; int parent[MAXN]; // 节点的父节点 int rank[MAXN]; // 节点所在集合的秩 int find(int x) { if (parent[x] != x) { parent[x] = find(parent[x]); } return parent[x]; } void unionSet(int x, int y) { int rootX = find(x); int rootY = find(y); if (rootX == rootY) return; if (rank[rootX] < rank[rootY]) { swap(rootX, rootY); } parent[rootY] = rootX; if (rank[rootX] == rank[rootY]) { rank[rootX]++; } } vector<Edge> kruskal(int n, vector<Edge>& edges) { // 初始化 for (int i = 0; i < n; i++) { parent[i] = i; rank[i] = 0; } // 将边按照权值从小到大排序 sort(edges.begin(), edges.end()); // 依次选择每条边 vector<Edge> result; for (Edge edge : edges) { if (find(edge.from) != find(edge.to)) { result.push_back(edge); unionSet(edge.from, edge.to); } } return result; } int main() { int n = 6; // 节点数 // 初始化边 vector<Edge> edges = { {0, 1, 6}, {0, 2, 1}, {0, 3, 5}, {1, 2, 5}, {1, 4, 3}, {2, 3, 5}, {2, 4, 6}, {2, 5, 4}, {3, 5, 2}, {4, 5, 6} }; vector<Edge> result = kruskal(n, edges); int sum = 0; for (Edge edge : result) { cout << edge.from << "-" << edge.to << " " << edge.weight << endl; sum += edge.weight; } cout << "Weight of MST: " << sum << endl; 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++中可以使用二维数组来表示邻接矩阵存储的图结构,其中数组的行和列分别表示图中的节点,数组中的值表示节点之间的边的权重。下面是封装的各种算法的介绍: 1. 深度优先搜索算法(DFS):从图的某个节点开始,沿着一条路径一直走到底,直到不能再走为止,然后回溯到前一个节点,继续走其他的路径,直到所有的节点都被访问过。这个算法可以用递归或者栈来实现。 2. 广度优先搜索算法(BFS):从图的某个节点开始,先访问它的所有邻居节点,然后再访问邻居节点的邻居节点,以此类推,直到所有的节点都被访问过。这个算法可以用队列来实现。 3. Prim算法:用于求解最小生成树,从一个节点开始,每次选择与当前节点相邻的权重最小的边所连接的节点,直到所有的节点都被访问过。这个算法可以用堆来实现。 4. Kruskal算法:也用于求解最小生成树,将所有的边按照权重从小到大排序,然后依次加入到生成树中,如果加入的边会形成环,则不加入。这个算法可以用并查集来实现。 5. Dijstra算法:用于求解单源最短路径,从一个节点开始,每次选择与当前节点距离最短的节点,然后更新其他节点到起点的距离,直到所有的节点都被访问过。这个算法可以用堆来实现。 6. Floyd算法:用于求解所有节点之间的最短路径,通过动态规划的方式,依次计算出所有节点之间的最短路径。这个算法的时间复杂度为O(n^3)。 下面是一些相关问题:
最小生成树是一种求无向图中生成树的算法,其中边的权重之和最小。常见的算法有Prim算法和Kruskal算法。以下是Prim算法和Kruskal算法的C++代码实现。 Prim算法: c++ #include <iostream> #include <vector> #include <queue> #include <cstring> using namespace std; const int N = 10010; const int INF = 0x3f3f3f3f; int n, m; int g[N][N]; int dist[N]; bool vis[N]; int prim() { memset(dist, INF, sizeof(dist)); memset(vis, false, sizeof(vis)); dist[1] = 0; int res = 0; for (int i = 0; i < n; i++) { int u = -1; for (int j = 1; j <= n; j++) { if (!vis[j] && (u == -1 || dist[j] < dist[u])) u = j; } vis[u] = true; res += dist[u]; for (int v = 1; v <= n; v++) { if (!vis[v]) dist[v] = min(dist[v], g[u][v]); } } return res; } int main() { cin >> n >> m; memset(g, INF, sizeof(g)); while (m--) { int a, b, c; cin >> a >> b >> c; g[a][b] = g[b][a] = c; } cout << prim() << endl; return 0; } Kruskal算法: c++ #include <iostream> #include <vector> #include <algorithm> using namespace std; const int N = 10010; int n, m; int p[N]; struct Edge { int a, b, w; bool operator<(const Edge& e) const { return w < e.w; } }edges[N]; int find(int x) { if (p[x] != x) p[x] = find(p[x]); return p[x]; } int kruskal() { int res = 0, cnt = 0; sort(edges, edges + m); for (int i = 1; i <= n; i++) p[i] = i; for (int i = 0; i < m; i++) { int a = edges[i].a, b = edges[i].b, w = edges[i].w; int pa = find(a), pb = find(b); if (pa != pb) { p[pa] = pb; res += w; cnt++; if (cnt == n - 1) break; } } return res; } int main() { cin >> n >> m; for (int i = 0; i < m; i++) { int a, b, c; cin >> a >> b >> c; edges[i] = {a, b, c}; } cout << kruskal() << endl; return 0; } 注意:以上代码均未做输入格式和边界处理,仅供参考。
Prim算法实现: #include <iostream> #include <vector> #include <queue> #include <cstring> using namespace std; const int MAXN = 1005; int n, m; int a[9] = {1, 1, 2, 2, 2, 3, 3, 4, 5}; int b[9] = {2, 4, 3, 5, 6, 5, 6, 6, 6}; int c[9] = {10, 30, 50, 40, 25, 35, 15, 20, 55}; int vis[MAXN]; int dis[MAXN]; vector> g[MAXN]; void prim() { memset(vis, 0, sizeof(vis)); memset(dis, 0x3f, sizeof(dis)); priority_queue, vector>, greater>> q; q.push(make_pair(0, 1)); dis[1] = 0; while (!q.empty()) { int x = q.top().second; q.pop(); if (vis[x]) continue; vis[x] = 1; for (auto& e : g[x]) { int y = e.first, w = e.second; if (!vis[y] && w < dis[y]) { dis[y] = w; q.push(make_pair(dis[y], y)); } } } } int main() { n = 6; m = 9; for (int i = 0; i < m; i++) { int u = a[i], v = b[i], w = c[i]; g[u].push_back(make_pair(v, w)); g[v].push_back(make_pair(u, w)); } prim(); int ans = 0; for (int i = 1; i <= n; i++) { ans += dis[i]; } cout << ans << endl; return 0; } Kruskal算法实现: #include <iostream> #include <algorithm> #include <vector> using namespace std; const int MAXN = 1005; int n, m; int fa[MAXN]; int a[9] = {1, 1, 2, 2, 2, 3, 3, 4, 5}; int b[9] = {2, 4, 3, 5, 6, 5, 6, 6, 6}; int c[9] = {10, 30, 50, 40, 25, 35, 15, 20, 55}; vector>> edge; int find(int x) { if (fa[x] == x) return x; return fa[x] = find(fa[x]); } void kruskal() { for (int i = 1; i <= n; i++) { fa[i] = i; } sort(edge.begin(), edge.end()); int cnt = 0, ans = 0; for (int i = 0; i < edge.size(); i++) { int x = edge[i].second.first, y = edge[i].second.second, w = edge[i].first; x = find(x); y = find(y); if (x != y) { fa[x] = y; cnt++; ans += w; } if (cnt == n - 1) break; } cout << ans << endl; } int main() { n = 6; m = 9; for (int i = 0; i < m; i++) { int u = a[i], v = b[i], w = c[i]; edge.push_back(make_pair(w, make_pair(u, v))); } kruskal(); return 0; }
根据提供的引用内容,以下是使用C++实现Prim算法和Kruskal算法求解最小生成树的代码: 1. Prim算法 c++ #include <iostream> #include <cstring> using namespace std; const int N = 510; int g[N][N], dist[N]; bool st[N]; int prim(int n) { memset(dist, 0x3f, sizeof dist); int res = 0; for (int i = 0; i < n; i++) { int t = -1; for (int j = 1; j <= n; j++) if (!st[j] && (t == -1 || dist[t] > dist[j])) t = j; if (i && dist[t] == 0x3f3f3f3f) return -1; if (i) res += dist[t]; st[t] = true; for (int j = 1; j <= n; j++) dist[j] = min(dist[j], g[t][j]); } return res; } int main() { int n, m; cin >> n >> m; memset(g, 0x3f, sizeof g); while (m--) { int a, b, c; cin >> a >> b >> c; g[a][b] = g[b][a] = min(g[a][b], c); } int t = prim(n); if (t == -1) puts("impossible"); else cout << t << endl; return 0; } 2. Kruskal算法 c++ #include <iostream> #include <algorithm> using namespace std; const int N = 200010; int p[N]; struct Edge { int a, b, w; bool operator< (const Edge &W) const { return w < W.w; } }edges[N]; int find(int x) { if (p[x] != x) p[x] = find(p[x]); return p[x]; } int main() { int n, m; cin >> n >> m; for (int i = 0; i < m; i++) cin >> edges[i].a >> edges[i].b >> edges[i].w; sort(edges, edges + m); for (int i = 1; i <= n; i++) p[i] = i; int res = 0, cnt = 0; for (int i = 0; i < m; i++) { int a = edges[i].a, b = edges[i].b, w = edges[i].w; a = find(a), b = find(b); if (a != b) { p[a] = b; res += w; cnt++; } } if (cnt < n - 1) puts("impossible"); else cout << res << endl; return 0; }
点云最小生成树是一种图论问题,可以使用Kruskal算法和Prim算法来解决。下面是一个使用Kruskal算法的C++代码示例,假设点云数据存储在一个二维数组中,其中每一行表示一个点的坐标信息。 c++ #include <iostream> #include <vector> #include <algorithm> using namespace std; const int MAX_N = 1000; // 最大点数 const int INF = 0x3f3f3f3f; // 无穷大 int n; // 点数 double dist[MAX_N][MAX_N]; // 点之间的距离 struct Edge { int u, v; // 边的两个端点 double w; // 边的权值 bool operator<(const Edge& other) const { return w < other.w; } }; int parent[MAX_N]; // 并查集数组 // 并查集查找根节点 int find(int x) { if (parent[x] != x) { parent[x] = find(parent[x]); } return parent[x]; } // Kruskal算法求最小生成树 vector<Edge> kruskal() { vector<Edge> edges; // 存储边的集合 for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { edges.push_back({i, j, dist[i][j]}); } } sort(edges.begin(), edges.end()); // 按边权排序 vector<Edge> mst; // 存储最小生成树的边 for (int i = 0; i < n; i++) { parent[i] = i; // 初始化并查集 } for (int i = 0; i < edges.size(); i++) { int u = edges[i].u, v = edges[i].v; int pu = find(u), pv = find(v); if (pu != pv) { // 如果不在同一个连通块中 parent[pu] = pv; // 合并连通块 mst.push_back(edges[i]); // 添加边到最小生成树 } } return mst; } int main() { // 读入点云数据 cin >> n; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { cin >> dist[i][j]; } } // 求解最小生成树 vector<Edge> mst = kruskal(); // 输出最小生成树的权值和 double sum = 0; for (int i = 0; i < mst.size(); i++) { sum += mst[i].w; } cout << sum << endl; return 0; } 这段代码使用了一个结构体Edge来表示一条边,重载了小于号运算符以便进行边权排序。kruskal()函数使用Kruskal算法求解最小生成树,并返回最小生成树的边集合。find()函数是并查集的查找根节点操作,parent数组存储每个节点的父亲节点。最后,代码读入点云数据,求解最小生成树并输出权值和。
以下是使用邻接矩阵实现图的算法和测试代码: 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数组输出即可。
实验目的: 学习最小生成树的算法,了解Kruskal和Prim算法的实现过程,掌握使用C++实现最小生成树的方法。 实验原理: 最小生成树是指在一个带权连通图中,选择一些边使得这些边的权值之和最小,并且这些边构成一棵树。常用的最小生成树算法有Kruskal算法和Prim算法。 Kruskal算法:按照边权值从小到大的顺序将边加入到生成树中,若加入该边会形成环,则不加入该边,直到生成树中有n-1条边为止。Kruskal算法的时间复杂度为O(ElogE)。 Prim算法:从一个点出发,将与该点相连的边加入到一个优先队列中,每次从队列中选出权值最小的边加入到生成树中,并将新加入的点的边继续加入队列,直到生成树中有n-1条边为止。Prim算法的时间复杂度为O(ElogV)。 实验步骤: 1.读入图的邻接矩阵或邻接表 2.选择Kruskal或Prim算法实现最小生成树 3.输出最小生成树的边集合以及权值之和 C++代码实现: Kruskal算法实现: #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=100010,M=200010; int h[N],e[M],ne[M],w[M],idx; int p[N]; int n,m; void add(int a,int b,int c) { e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++; } int find(int x) { if(p[x]!=x) p[x]=find(p[x]); return p[x]; } struct Edge { int a,b,w; bool operator < (const Edge &t) const { return w<t.w; } }edges[M]; int kruskal() { sort(edges,edges+m); for(int i=1;i<=n;i++) p[i]=i; int res=0,cnt=0; for(int i=0;i<m;i++) { int a=edges[i].a,b=edges[i].b,w=edges[i].w; a=find(a),b=find(b); if(a!=b) { p[a]=b; res+=w; cnt++; if(cnt==n-1) break; } } if(cnt<n-1) return -1; return res; } int main() { scanf("%d%d",&n,&m); for(int i=0;i<m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); edges[i]={a,b,c}; } int t=kruskal(); if(t==-1) puts("impossible"); else printf("%d\n",t); return 0; } Prim算法实现: #include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=100010,M=200010; int h[N],e[M],ne[M],w[M],idx; int dist[N]; bool st[N]; int n,m; void add(int a,int b,int c) { e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++; } int prim() { memset(dist,0x3f,sizeof dist); dist[1]=0; priority_queue,vector>,greater>> heap; heap.push({0,1}); int res=0; while(heap.size()) { auto t=heap.top(); heap.pop(); int ver=t.second,distance=t.first; if(st[ver]) continue; st[ver]=true; res+=distance; for(int i=h[ver];~i;i=ne[i]) { int j=e[i]; if(dist[j]>w[i]) { dist[j]=w[i]; heap.push({dist[j],j}); } } } return res; } int main() { memset(h,-1,sizeof h); scanf("%d%d",&n,&m); for(int i=0;i<m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); add(a,b,c),add(b,a,c); } int t=prim(); printf("%d\n",t); return 0; } 实验结论: 本次实验通过Kruskal算法和Prim算法实现了最小生成树的生成,了解了它们的实现过程,并掌握了使用C++实现最小生成树的方法。
以下是C++实现的Prim算法和Kruskal算法的最小生成树代码示例: Prim算法: c++ #include <iostream> #include <cstring> using namespace std; const int N = 1005; const int INF = 0x3f3f3f3f; int n, m; int g[N][N]; int dist[N]; bool st[N]; int prim() { memset(dist, 0x3f, sizeof dist); int res = 0; for (int i = 0; i < n; ++i) { int t = -1; for (int j = 1; j <= n; ++j) if (!st[j] && (t == -1 || dist[t] > dist[j])) t = j; if (i && dist[t] == INF) return INF; if (i) res += dist[t]; st[t] = true; for (int j = 1; j <= n; ++j) dist[j] = min(dist[j], g[t][j]); } return res; } int main() { cin >> n >> m; memset(g, 0x3f, sizeof g); while (m--) { int a, b, c; cin >> a >> b >> c; g[a][b] = g[b][a] = min(g[a][b], c); } int t = prim(); if (t == INF) puts("impossible"); else cout << t << endl; return 0; } Kruskal算法: c++ #include <iostream> #include <algorithm> using namespace std; const int N = 200005; int n, m; int p[N]; struct Edge { int a, b, w; bool operator< (const Edge& t) const { return w < t.w; } }edges[N]; int find(int x) { if (p[x] != x) p[x] = find(p[x]); return p[x]; } int kruskal() { sort(edges, edges + m); for (int i = 1; i <= n; ++i) p[i] = i; int res = 0, cnt = 0; for (int i = 0; i < m && cnt < n - 1; ++i) { int a = edges[i].a, b = edges[i].b, w = edges[i].w; a = find(a), b = find(b); if (a != b) { p[a] = b; res += w; ++cnt; } } if (cnt < n - 1) return -1; return res; } int main() { cin >> n >> m; for (int i = 0; i < m; ++i) cin >> edges[i].a >> edges[i].b >> edges[i].w; int t = kruskal(); if (t == -1) puts("impossible"); else cout << t << endl; return 0; } 以上两种算法都可以求解无向图的最小生成树,Prim算法的时间复杂度为O(n^2),适用于稠密图;Kruskal算法的时间复杂度为O(mlogm),适用于稀疏图。

最新推荐

C++使用Kruskal和Prim算法实现最小生成树

主要介绍了C++使用Kruskal和Prim算法实现最小生成树,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

ns_strings_zh.xml

ns_strings_zh.xml

基于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�

valueError: Pandas data cast to numpy dtype of object. Check input data with np.asarray(data).

这个错误通常发生在使用 Pandas DataFrame 时,其中包含了一些不能被转换为数字类型的数据。 解决方法是使用 `pd.to_numeric()` 函数将数据转换为数字类型。例如: ```python import pandas as pd import numpy as np # 创建一个包含字符串和数字的 DataFrame df = pd.DataFrame({'A': ['a', 'b', 'c'], 'B': [1, 2, '3']}) # 尝试将整个 DataFrame 转换为数字类型会报错 np.asarray(df, dtype=np.float) # 使

基于VC--的五子棋程序设计与实现毕业设计.doc

基于VC--的五子棋程序设计与实现毕业设计.doc

体系结构驱动的普遍性应用程序中

体系结构驱动的普遍性应用程序的自主适应艾蒂安·甘德里勒引用此版本:艾蒂安·甘德里勒。由体系结构驱动的普遍性应用程序的自主适应。无处不在的计算。格勒诺布尔大学,2014年。法语。NNT:2014GRENM078。电话:01215004HAL ID:电话:01215004https://theses.hal.science/tel-01215004提交日期:2015年HAL是一个多学科的开放存取档案馆,用于存放和传播科学研究论文,无论它们是否被公开。论文可以来自法国或国外的教学和研究机构,也可以来自公共或私人研究中心。L’archive ouverte pluridisciplinaire论文要获得的等级格勒诺布尔大学博士专业:计算机科学部长令:2006年提交人艾蒂安·G·安德里尔论文由Philippe LAlanda指导由Stephanie CHollet共同指导在格勒诺布尔计算机科学实验室编写数学、信息科学与技术、计算机科学博士体系结构驱动的普遍性应用程序的自主适应论文�