图论入门-Kruskal算法
Posted 123zhh-helloworld
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图论入门-Kruskal算法相关的知识,希望对你有一定的参考价值。
1943: 最优布线问题Time Limit: 1 Sec Memory Limit: 128 MB 64bit IO Format: %lldSubmitted: 33 Accepted: 19 [Submit][Status][Web Board] Description 学校有n台计算机,为了方便数据传输,现要将它们用数据线连接起来。两台计算机被连接是指它们间有数据线连接。由于计算机所处的位置不同,因此不同的两台计算机的连接费用往往是不同的。
当然,如果将任意两台计算机都用数据线连接,费用将是相当庞大的。为了节省费用,我们采用数据的间接传输手段,即一台计算机可以间接的通过若干台计算机(作为中转)来实现与另一台计算机的连接。
现在由你负责连接这些计算机,任务是使任意两台计算机都连通(不管是直接的或间接的)。
Input多组测试数据。
第一行为整数n(2<=n<=100),表示计算机的数目。
此后的n行,每行n个整数。第x+1行y列的整数表示直接连接第x台计算机和第y台计算机的费用。
Output输出一个整数,表示最小的连接费用。
Sample Input3
0 1 2
1 0 1
2 1 0
Sample Output2
|
这个题是个很基础的最小生成树的题, 最小生成树的题有Prime(普利姆)算法和Kruskal(克鲁斯卡尔)算法可以解决, 个人推荐Kruskal算法, 很简单。 下面挂上Kruskal算法的代码。 1 #include<iostream> 2 #include<cstdio> 3 #include<iomanip> 4 #include<queue> 5 #include<map> 6 #include<set> 7 #include<stack> 8 #include<list> 9 #include<algorithm> 10 #include<cmath> 11 #include<cstring> 12 #include<string> 13 #include<sstream> 14 #include<fstream> 15 #define go(t) int t; cin>>t; while(t--) 16 #define ll long long 17 #define rep(i, a, n) for(int i = a; i < n; i++) 18 #define res(i, a, n) for(int i = a - 1; i >= n; i--) 19 using namespace std; 20 const int inf = -1; 21 const int mod = 1e9 + 7; 22 const double pi = acos(-1); 23 const int N = 120; 24 25 //创建结构体存数据, 以及动手写一个比较大小的函数 26 /*******************************************/ 27 /**/struct node{ 28 /**/ int x, y, z; 29 /**/}a[N * N]; 30 /**/ 31 /**/bool com(node aa, node bb){ 32 /**/ return aa.z < bb.z; 33 /**/} 34 /*******************************************/ 35 36 //但是我按下面这种写法来居然会报错, 是我还是太年轻吗 37 /* 38 struct node{ 39 int x, y, z; 40 bool operator < (node &a){ 41 return z < a.z; 42 } 43 }a[N * N]; 44 */ 45 46 //然后接下就是并查集的操作了 47 int fa[N], n, m; 48 49 //初始化, 先令fa[i] = i, 这里不需要val数组来存放权值, 所以就没写 50 void init(){ 51 rep(i, 0, n + 1) fa[i] = i; 52 } 53 54 //查找根节点, 还是和并查集一样, 注意fa[x] = , 上面的init写了记得用上, 别像我一样, 老是忘了用 55 int Find(int x){ 56 return x == fa[x] ? x : fa[x] = Find(fa[x]); 57 } 58 59 int main(){ 60 while(cin >> n){ 61 init(); 62 int idx = 1; //加个idx方便数据的输入 63 rep(i, 1, n + 1){ 64 rep(j, 1, n + 1){ 65 a[idx].x = i; 66 a[idx].y = j; 67 cin >> a[idx++].z; 68 } 69 } 70 sort(a + 1, a + n * n + 1, com); 71 //排个序, 没有重载小于号的话, 可以在sort加上第三个参数, 也就是比较函数 72 73 //精彩的部分来了, ans是answer的缩写, 即为最终答案, tot是选择连接的线路的条数 74 int ans = 0, tot = 0; 75 76 rep(i, 1, n * n + 1){ 77 int x = a[i].x, y = a[i].y; 78 x = Find(x); y = Find(y); 79 80 if(x != y){ 81 fa[x] = y; //到这一步为止是并查集的操作 82 83 //解释一下这里, 连接n个电脑只需要n - 1条线路就可以了 84 //所以我们选择最短的n - 1条线路, 这也是之前要先排序一下的目的 85 //但是这n - 1条线路连接起来的图形不能有环, 所以x不能等于y 86 ans += a[i].z; 87 tot++; 88 } 89 //如果已经选好了n - 1条线路, 就可以退出了 90 if(tot == n - 1) break; 91 } 92 //由题意可得, 一定会有解, 所以直接输出结果就好了 93 cout << ans << endl; 94 } 95 return 0; 96 } 对于克鲁斯卡尔算法, 我个人感觉是贪心算法和并查集的结合, 操作起来很简单, 理解起来也毫无困难。 对于新手来说, 应该是非常友好的一种算法了。 |
以上是关于图论入门-Kruskal算法的主要内容,如果未能解决你的问题,请参考以下文章