Kruskal算法(最小生成树)

昨晚被最小生成树的题卡了一晚上,好不容易才搞明白
就以这道题为例吧
线路规划
题目我放到最后

最小生成树有两种算法Kruskal和Prim
两种算法其实都是贪心
还是蒟蒻的我现在还只会Kruskal算法
就只写这一种算法了

最小生成树有两个性质

  • 最小生成树不能形成回路
  • 最小生成树的边数等于点数减一

Kruskal算法:

1. 快排边长,用贪心的思想每次都优先选取权值较小的边
2. 建立并查集,判断是否连成环。如果两个点已经在一个并查集里面,若连接,就会形成一个环
3. 当边的数量为点的数量减一时,最小生成树已经建成了,退出循环

蒟蒻好不容易通过的代码

int f[101011];//并查集 
int n,m,cnt;
ll ans;
struct node
{
	int x;
	int y;
	int val;
}a[101011];

int find(int root)//找根节点 
{
	while(root != f[root])
	{
		root = f[root] = f[f[root]];
	}
	return root;
}

bool cmp(node t1,node t2)
{
	return t1.val < t2.val;
	//按边的权值升序排列 
}

void kruskal()
{
	ans=0;
	cnt=0;
	for(int i=0;i<m;i++)
	{
		int root1,root2;
		root1 = find(a[i].x);
		root2 = find(a[i].y);
		if(root1 == root2)
		{
			continue;
			//这两个点已经连通,存在于一个并查集中 
		}
		ans += a[i].val;
		f[root1] = root2;//合并为一个并查集
		if(++cnt == n-1) break;
		//循环结束条件:边的数量为点的数量减一 
	}
}

int main()
{
	cin >> n >> m;
	for(int i=0;i<n;i++)
	{
		f[i]=i;
		//并查集初始化,每个人是自己的根节点
	}
	for(int i=0;i<m;i++)
	{
		cin >> a[i].x >> a[i].y >> a[i].val;
	}
	sort(a,a+m,cmp);
	kruskal(); 
	cout << ans << endl;
	return 0;
}

问题 A: 线路规划
时间限制: 1 Sec 内存限制: 128 MB

题目描述
有n 个村庄之间需要架设通信线路,使得任意两个村庄之间均可通信。两个村庄a, b 间可通信,当且仅当它们之间存在一条通信线路或者存在村庄c 使得a,c 和b,c 间均可通信。给出村庄之间架设通信线路的代价,求出最小的总代价。
输入
第一行包含两个整数n,m,分别表示村庄数量和可以架设通信线路的村庄对数。以下m 行,每行三个整数a,b,c,表示村庄a,b之间架设线路的代价为c(村庄从0 开始编号)。
输出
一个整数,最小总代价。
样例输入 Copy
3 3
0 1 1
1 2 1
2 0 3
样例输出 Copy
2
提示
对于50% 的数据,n<=100,m <=n^2
对于全部数据,1<=n<=10^5; n-1<=m<=10^5,所有代价均在[0, 10^6] 范围内,保证问题有解。

你可能感兴趣的:(最小生成树)