题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz
。
输入格式
第一行包含两个整数 N,M,表示该图共有 N 个结点和 M 条无向边。
接下来 M 行每行包含三个整数 Xi,Yi,Zi,表示有一条长度为 Zi 的无向边连接结点 Xi,Yi。
输出格式
如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz
。
输入输出样例
输入 #1
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
输出 #1
7
因为最近要轮到我讲最小生成树了,遂来学一学。
用这一道简单的模板题,熟悉一下简单的kruskal算法。
kruskal算法流程
并查集算法代码
来源:https://blog.csdn.net/DuanLiuchang/article/details/105060654
int pre[1010]; //存放第i个元素的父节点
int unionsearch(int root) //查找根结点
{
int son, tmp;
son = root;
while(root != pre[root]) //寻找根结点
root = pre[root];
while(son != root) //路径压缩
{
tmp = pre[son];
pre[son] = root;
son = tmp;
}
return root;
}
void join(int root1, int root2) //判断是否连通,不连通就合并
{
int x, y;
x = unionsearch(root1);
y = unionsearch(root2);
if(x != y) //如果不连通,就把它们所在的连通分支合并
pre[x] = y;
}
本题ac代码
#include<bits/stdc++.h> //kruskal算法
using namespace std;
int N,M;
int ans=0,cou=0;
int pre[10000]; //并查集数组
struct edge{ //存边的结构体
int start,to; //两点
int w; //权重
}p[500000];
bool cmp(edge a,edge b)
{
return a.w<b.w; //按权重小到大排序
}
int find(int x)
{
while(x!=pre[x]) //本题要求不是很高,遂没写路径压缩
x = pre[x];
return x;
}
void kruskal(void)
{
for(int i=1;i<M;i++)
{
int u = find(p[i].start);
int v = find(p[i].to);
if(u==v)
{
continue;
}
else
{
ans += p[i].w;
pre[v] = u; //连通并查集
cou++;
if(cou==N-1) break; //找到n-1边了,结束
}
}
}
int main()
{
cin>>N>>M; //N个结点 M条无向边
int x,y,z;
for(int i=1;i<=N;i++)
pre[i] = i; //初始化并查集(上级为其本身)
for(int i=1;i<=M;i++) //存边
{
cin>>x>>y>>z;
p[i].start = x;
p[i].to = y;
p[i].w = z;
}
sort(p+1,p+M+1,cmp);
kruskal();
if(cou==N-1) cout<<ans<<endl;
else cout<<"orz\n";
return 0;
}