题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz
。
输入格式
第一行包含两个整数N,M,表示该图共有 N 个结点和 M 条无向边。
接下来 M 行每行包含三个整数 Xi,Yi,Zi,表示有一条长度为 Zi 的无向边连接结点 Xi,Yi。
输出格式
如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz
题目分析
这道题是一个最小生成树算法的实现,使用的是Kruskal算法。它通过给定的图找到一个权值最小的生成树。
代码中的数组用于保存每个节点的父节点,用于路径压缩操作。用一个
变量用于保存生成树的权值和。
首先,从输入中读取图的节点数n
和边数m
。然后,依次读取每条边的起点、终点和权值,并将它们保存在结构体数组中。
接下来,对结构体数组进行排序,按照边权值从小到大进行快速排序。
然后,初始化每个节点的父节点为自身。
接下来,遍历排序后的边,如果边的起点和终点不在同一个集合中,则将它们合并,并将边的权值加到权值上,并将计数加1。
最后,判断生成树的边数是否等于节点数减1,如果不相等则输出"orz",表示图不连通;如果相等则输出生成树的权值和。
题目代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int fat[5001];
int tot;
struct node{
int x,y,z;//结构体保存起点x,终点y,以及边权z
}f[200001];
int find(int x)//路径压缩
{
if(fat[x]!=x) fat[x]=find(fat[x]);
return fat[x];
}
void unionn(int x,int y)//合并
{
int x1=find(x),y1=find(y);
if(x1==y1) return;
else fat[y1]=x1;
}
bool cmp(node a,node b)
{
return a.z<b.z;
}
int main()
{
int m,n;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&f[i].x,&f[i].y,&f[i].z);
for(int i=1;i<=n;i++) fat[i]=i;
sort(f+1,f+m+1,cmp);
int k=0;//计数
for(int i=1;i<=m;i++)
{
if(find(f[i].x)!=find(f[i].y))//不在同一集合内
{
unionn(f[i].x,f[i].y);
tot+=f[i].z;//计算权值和
k++;
}
}
if(k<n-1) printf("orz");//判断是否连通
else printf("%d",tot);
}