图论入门-Kruskal算法

1943: 最优布线问题

Time Limit: 1 Sec  Memory Limit: 128 MB   64bit IO Format: %lld
Submitted: 33  Accepted: 19
[Submit][Status][Web Board]

Description

  学校有n台计算机,为了方便数据传输,现要将它们用数据线连接起来。两台计算机被连接是指它们间有数据线连接。由于计算机所处的位置不同,因此不同的两台计算机的连接费用往往是不同的。

当然,如果将任意两台计算机都用数据线连接,费用将是相当庞大的。为了节省费用,我们采用数据的间接传输手段,即一台计算机可以间接的通过若干台计算机(作为中转)来实现与另一台计算机的连接。

  现在由你负责连接这些计算机,任务是使任意两台计算机都连通(不管是直接的或间接的)。

Input

多组测试数据。

第一行为整数n(2<=n<=100),表示计算机的数目。

此后的n行,每行n个整数。第x+1行y列的整数表示直接连接第x台计算机和第y台计算机的费用。

Output

输出一个整数,表示最小的连接费用。

Sample Input

3
0 1 2
1 0 1
2 1 0

Sample Output

2

题目连接:http://acm.wust.edu.cn/problem.php?id=1943&soj=0


  这个题是个很基础的最小生成树的题, 最小生成树的题有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 }

  对于克鲁斯卡尔算法, 我个人感觉是贪心算法和并查集的结合, 操作起来很简单, 理解起来也毫无困难。 对于新手来说, 应该是非常友好的一种算法了。

原文地址:https://www.cnblogs.com/123zhh-helloworld/p/9102617.html

时间: 2025-01-31 15:11:46

图论入门-Kruskal算法的相关文章

图论-最小生成树-Kruskal算法

有关概念: 最小生成树:在连通图G中,连接图G所有顶点且总权最小的边构成的树 思路: 首先对边按权从小到大排序,紧接着枚举每一条边,如果两个结点的祖先结点不同(并查集),则连上此边,直到边数等于结点数-1即可 邻接矩阵输入,用类邻接表存储方式存边 1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 #define MAXN 5 #define MAXM 6 int father[MAXN],n,m,cn

HDU 1233 还是畅通工程【最小生成树入门题,Kruskal算法+Prim算法】

还是畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 39929    Accepted Submission(s): 18144 Problem Description 某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离.省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路

Prim算法和Kruskal算法(图论中的最小生成树算法)

最小生成树在一个图中可以有多个,但是如果一个图中边的权值互不相同的话,那么最小生成树只可能存在一个,用反证法很容易就证明出来了. 当然最小生成树也是一个图中包含所有节点的权值和最低的子图. 在一个图中权值最小的那个边一定在最小生成树中,如果一个图包含环,环中权值最大的边一定不在最小生成树中,还有就是连接图的任意两个划分的边中权值最短的那一条一定在最小生成树中. 下面介绍两个算法. Prim算法 Prim算法就是以任意一个点为源点,将所有点分为两组,一组是已经在最小生成树上的点,另一组是还未在最小

HDU 1102 Constructing Roads (最小生成树+Kruskal算法入门)

[题目链接]:click here~~ [题目大意]:已知某几条道路已经修完,求全部道路要通路的最小花费 [解题思路]:基础的Kruskal算法了,按照边的权值从小到大排序一遍,符合条件加入到生成树中 代码: /* Author:HRW kruskal+并查集 */ #include <bits/stdc++.h> using namespace std; const int max_v=105; const int inf=0x3f3f3f3f; int u,v,n,m,a,b; int f

【图论】【最小生成树】Prim和Kruskal算法

在数据结构的教材上,讲到的图的最小生成树算法有两种,一种是Prim(普利姆)算法,一种是Kruskal(克鲁斯卡尔)算法. 两种算法的生成思路有所不同: Prim算法: 算法思想: 算法思想就是每次找到一个距离生成集合最近的点,加入,然后更新距离剩余点之间的距离,继续迭代. 算法步骤: 1.任意选择一个点作为起点,将该点标记为已加入最小生成树,使用一个数组表示该点已加入,join[i] = 1表示i点已加入集合: 2.将最小生成树集合作为整体,计算到其他未加入该集合的点(jion[i] == 0

最小生成树-Prim算法和Kruskal算法

原文链接:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小.该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现:并在195

转载:最小生成树-Prim算法和Kruskal算法

本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小.该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:

kruskal算法-Pascal

马上就快要考试了,然而突然发现自己图论已经废了,于是再都打一遍练练手...... 1 const 2 maxn=100; 3 maxe=maxn*maxn; 4 5 type 6 edge=record //edge记录每一条边,a,b为它所连接的两个点,len为边长 7 a,b:longint; 8 len:longint; 9 end; 10 11 var 12 edges:array[0..maxe]of edge; 13 p,r:array[0..maxn]of longint; 14

数据结构与算法系列----最小生成树(Prim算法&amp;amp;Kruskal算法)

 一:Prim算法       1.概览 普里姆算法(Prim算法).图论中的一种算法.可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中.不但包含了连通图里的全部顶点(英语:Vertex (graph theory)).且其全部边的权值之和亦为最小. 该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现.并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现:1959年,艾兹格·迪科斯彻再次发现了该