最小生成树之kruskal——洛谷P3366

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);
}

猜你喜欢

转载自blog.csdn.net/qq_37230495/article/details/88351465