kruskal最小生成树:把边从小到大排序,然后用并查集(并查集有关内容戳这里)的思想,如果这条边的两个定点分别属于不同的集合,那么就把这两个定点合并在一个集合,并把这条边记录下来,如果有n个定点,那么最小生成树就有n-1条边,即要合并n-1次,记录n-1次。
题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz
输入输出格式
输入格式:
第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,M<=200000)
接下来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
附上代码如下:
#include<stdio.h>
#include<algorithm>
using namespace std;
int N,M;
int a[5001];
struct Edge
{
int from,to,dis;//从from来到to去,距离为dis
}e[200001];
bool cmp(Edge x,Edge y)
{
return x.dis<y.dis;
}
int father(int x)
{
if(a[x]==x)
return x;
a[x]=father(a[x]);
return father(a[x]);
}
bool check(int x,int y)
{
if(father(x)==father(y))
return true;
else return false;
}
void merge(int x,int y)
{
if(check(x,y)==false)
a[father(x)]=father(y);
}
int kruskal()
{
int sum=0;//记录最小边的和
int cnt=0;//记录已经确定多少条边
int x,y;
for(int i=1;i<=M;i++)
{
x=father(e[i].from);
y=father(e[i].to);
if(x!=y)
{
sum=sum+e[i].dis;
merge(x,y);
cnt++;
}
if(cnt==N-1)
return sum;
}
if(cnt<N-1) //该图不连通
return -1;
}
int main()
{
scanf("%d %d",&N,&M);
for(int i=1;i<=M;i++)
scanf("%d %d %d",&e[i].from,&e[i].to,&e[i].dis);
sort(e+1,e+M+1,cmp);
for(int i=1;i<=N;i++)//初始化:让每个元素的祖宗都指向它自己
a[i]=i;
int temp;
temp=kruskal();
if(temp==-1)
printf("orz\n");
else printf("%d\n",temp);
}