201812-4 数据中心(kruskal)

考场上的时候被题目完全蒙住了,当时状态也不好,前几次考试每次考试当天就头晕感冒流鼻涕

好的,以上都是借口,自己没有好好复习才是真的...

题目:

好的,以上题目简述就是:给你一个无向连通图,求它的最小生成树的最大边,姐妹们,如果你们考场看懂了题目带了数据结构书或者会krukal又怎么不会得分呢?

我就是没看懂题目得人啊!不过,通过我今天的验证,发现就算我看懂了题目我也不一定得分,因为我运行错误orz...

就是简单的使用了一下kruskal,整个算法清晰易懂

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<algorithm>
 4 #include<iostream>
 5 using namespace std;
 6 //第一次提交:运行错误,查看代码,没啥问题啊???
 7 //第二次提交:修改MAX_VEX = 10^5, 改为5 * 1e5 + 10 ,记住乘方的表示方法 
 8 //...
 9 //第八次提交,100分,修改seek函数,由原来的while循环变为条件递归调用!!!然后在找到输出key的地方由原来条件判断来查找i,变成了最后直接计算查找i
10 //姐妹们,要记住当整个测试数据很大的时候,即使你的计算即使if,但是放到while里面,该大的数据还是大,我们尽量一点点抠时间总能给你节约出来 
11 const int MAX_VEX = 5*1e5 + 10;
12 int set[MAX_VEX];
13 typedef struct edged{
14     int bv, ev, w;
15 }Edges;
16 Edges edgeset[2 * MAX_VEX];
17 
18 bool cmp(Edges a,Edges b){
19     return a.w < b.w;
20 } 
21 
22 int seeks(int v){
23     return set[v] == v ? v : set[v] = seeks(set[v]);
24 }
25 
26 int kruskal(int n, int m){
27     int v1, v2, i;
28     for(i = 1; i <= m; i++){
29         set[i] = i;
30     }
31     int u = 0;//u记录连接的边的数量,当u = n-1时,已经构造处一棵树 
32     int key;
33     i = 0;
34     while(u < n-1){
35         v1 = seeks(edgeset[i].bv);//确定边的顶点所在连通分量的根节点
36         v2 = seeks(edgeset[i].ev);
37         if(v1 != v2){
38             set[v1] = v2;
39             u += 1;
40         }
41         i++;
42     }
43     i = i-1;
44     key = edgeset[i].w;
45     return key;
46 }
47 
48 int main(){
49     int n, m, root;
50     cin >> n >> m >> root;
51     for(int i = 1; i <= m; i++){
52         cin >> edgeset[i].bv >> edgeset[i].ev >> edgeset[i].w;
53     }
54     sort(edgeset+1,edgeset+m+1,cmp);//对边集数组按权值升序排序,其中n为元素个数,即图的边数 
55     int t = kruskal(n, m);
56     cout << t;
57     return 0;
58 }
View Code

我从题目给大家简略(粗糙带懵逼)的分析一下:

为什么说是求最小生成树的最大边呢?

1:先求每一层的最大边

2:将所有层最大边比较求最大边

也就是求整棵树的最大边

那要节约时间当然是所用的边的权值越小越好

假设最小生成树的最大边a不是题目所得最求生成树最大边b,即a > b,那么就是存在比最小生成树使用更小边得到的生成树,obviously,与最小生成树的定义矛盾了,所以a <= b

Therefore 我们需要求无向连通图的最小生成树

普遍使用的算法是prim和kruskal,但是prim使用了邻接矩阵来表示图的关系,适用于边数多顶点少的情况,但是这道题的顶点最大值上了10的5次方,很容易使用数组越界,为了保险起见,我使用了kruskal,结构体占占空间就好了

说一下我在提交答案时出现的错误,给大家一个小小的经验或者说是给我自己提个醒

乘方的表示:切记啊切记,不能直接表示10^4,而是使用1e4,最好大家开空间的时候往额定值大了开,这样总比一不小心开小了好,由于这个错误,我报出了运行错误

运行超时:这时候已经得到70分了,但是超时了,所以我就去看看大佬们的代码,一点一点去抠自己的时间,while循环里的判断拿出来,while变成递归调用,嗯,还是挺有用的

渣渣之开心~

 

 

 

转载于:https://www.cnblogs.com/mlblog27/p/10544429.html

### Kruskal算法生成最小生成树的过程 Kruskal算法是一种贪心算法,用于构造图的最小生成树。其核心思想是按边的权重从小到大排序,依次选择边,同时使用并查集结构确保每次选择的边不会形成环。最终,生成的树包含图中所有顶点,并且所有边的权值之和最小[^1]。 #### 图的基本信息 给定图包含 4 个顶点和 5 条边,具体信息如下: - 边 1-2,权重 2 - 边 1-3,权重 2 - 边 1-4,权重 3 - 边 2-3,权重 4 - 边 3-4,权重 3 #### Kruskal算法的执行过程 1. **边排序**:将所有边按照权重从小到大排序。排序后的边顺序为: - 边 1-2(权重 2) - 边 1-3(权重 2) - 边 1-4(权重 3) - 边 3-4(权重 3) - 边 2-3(权重 4) 2. **初始化并查集**:每个顶点初始属于自己的集合,即父节点为自身。 3. **依次处理每条边**: - 处理边 1-2:1 和 2 不在同一集合,合并,加入该边。 - 处理边 1-3:1 和 3 不在同一集合,合并,加入该边。 - 处理边 1-4:1 和 4 不在同一集合,合并,加入该边。 - 处理边 3-4:3 和 4 已在同一集合,跳过。 - 处理边 2-3:2 和 3 已在同一集合,跳过。 4. **生成的最小生成树**:包含边 1-2(权重 2)、1-3(权重 2)、1-4(权重 3),总权重为 7。 #### 最小生成树的结构 生成的最小生成树包含以下边: - 1 连接 2 - 1 连接 3 - 1 连接 4 该树的结构是以节点 1 为中心,连接节点 2、3、4,形成一个星型结构。 #### 并查集的实现 并查集在 Kruskal 算法中用于高效判断两个节点是否属于同一集合,并支持快速合并操作。实现方式包括路径压缩和按秩合并,以提高查找和合并的效率。 ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; struct Edge { int u, v, weight; bool operator<(const Edge& other) const { return weight < other.weight; } }; int find(vector<int>& parent, int x) { if (parent[x] != x) parent[x] = find(parent, parent[x]); // 路径压缩 return parent[x]; } void unite(vector<int>& parent, vector<int>& rank, int x, int y) { int rootX = find(parent, x); int rootY = find(parent, y); if (rootX != rootY) { if (rank[rootX] < rank[rootY]) // 按秩合并 swap(rootX, rootY); parent[rootY] = rootX; if (rank[rootX] == rank[rootY]) rank[rootX]++; } } int kruskalMST(int n, vector<Edge>& edges) { vector<int> parent(n + 1); vector<int> rank(n + 1, 0); for (int i = 1; i <= n; ++i) parent[i] = i; sort(edges.begin(), edges.end()); int totalWeight = 0; for (const auto& edge : edges) { if (find(parent, edge.u) != find(parent, edge.v)) { unite(parent, rank, edge.u, edge.v); totalWeight += edge.weight; } } return totalWeight; } int main() { int n = 4; vector<Edge> edges = { {1, 2, 2}, {1, 3, 2}, {1, 4, 3}, {3, 4, 3}, {2, 3, 4} }; int result = kruskalMST(n, edges); cout << "Total weight of MST: " << result << endl; return 0; } ``` #### 最小生成树的可视化结构 生成的最小生成树可以表示为以下图结构: ``` 1 / | \ 2 3 4 ``` 其中边的权重分别为: - 1-2(权重 2) - 1-3(权重 2) - 1-4(权重 3) #### 最小生成树的验证 通过 Kruskal 算法和并查集结合的方式,能够确保每次选择的边不会形成环,并且最终生成的树是连接所有顶点的最小生成树。由于算法始终选择当前最小权重的边,因此生成的树权值之和最小[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值