- 基本介绍
- 模板题目
- 代码实现
基本介绍
最小生成树问题一般有两种解法 Prim和Kruskal 因为之前学过并查集所以果断选择先学后者
Kruskal是一种利用并查集来求解最小生成树的算法 它将每一个联通块当作一个集合
先将边按从小到大的顺序排序 现在每一个点都是孤立的 并且自己成为一个集合 然后按排好的顺序枚举边 如果边连着两个集合 就加入最小生成树 一直到选出来n-1条边
用结构体存储 起点 终点 长度
struct point{
int x;
int y;
int z;
};
point a[size];
自定义sort
bool cmp(point a,point b)
{
return a.z<b.z;
}
感觉梳理不出什么来 都挺好理解的…
直接结合一下模板题目吧
模板题目
题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz
输入输出格式
输入格式:
第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,M<=200000)
接下来M行每行包含三个整数Xi、Yi、Zi,表示有一条长度为Zi的无向边连接结点Xi、Yi
输出格式:
输出包含一个数,即最小生成树的各边的长度之和;如果该图不连通则输出orz
输入输出样例
输入样例:
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
输出样例:
7
代码实现
代码修改日期:2017.9.12下午
====================================================================
#include<iostream>
#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
#define in = read()
typedef long long ll;
const ll size = 1000000 + 10000;
struct kruskal{ ll x,y,z;}point[size];
ll n,m;
ll site,ans,total;
ll father[size];
inline ll read(){
ll num = 0 , f = 1; char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') f = -1;
ch = getchar();
}
while(isdigit(ch)){
num = num*10 + ch - '0';
ch = getchar();
}
return num*f;
}
inline void add(ll x,ll y,ll z){
point[++site].x = x;
point[site].y = y;
point[site].z = z;
}
inline bool cmp(kruskal a,kruskal b){ return a.z<b.z;}
ll find(ll x){
if(father[x] != x)
father[x] = find(father[x]);
return father[x];
}
inline void unionn(ll x,ll y){
x = find(x); y = find(y);
father[y] = x;
}
int main(){
n in; m in;
for(int i=1;i<=n;i++) father[i] = i;
for(int i=1;i<=m;i++){
ll x,y,z; x in; y in; z in;
add(x,y,z); add(y,x,z);
}
sort(point+1,point+site+1,cmp);
for(int i=1;i<=site;i++){
ll x = point[i].x , y = point[i].y;
if(find(x) != find(y)){
unionn(x,y);
ans += point[i].z;
total ++;
if(total == n - 1) break;
}
}
printf("%d",ans);
}
//COYG