最小生成树kruskal算法

kruskal算法可以解决最小最大生成树问题,要一个info结构体来储存两个相互连接的电以及它们之间的权值,以及需要并查集的知识来完成边的选取。

并查集需要一个数组来储存需要的信息,pre数组,pre[i]表示结点的祖先结点,pre[i]初始化为i。

并查集需要两个函数来完成相应的操作,Find(int a)和Union(int a, int b) Find函数是用来查找a的祖先,Union函数是用来合并两个结点

kruskal算法思路如下:

1.对于所有的边,按照边的权值的大小从小到大排序

2.将排序好的结构体从小到大遍历,对于一条边上的两个点判断这两个点是否在同一颗树里,如果是就跳过,如果不是就合并这两个点。

3.重复2直到选了n-1条边(n为点的个数)如果选不到n条边说明该图不是连通图

来个例子

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARGFvQ2FvUmVuX19f,size_20,color_FFFFFF,t_70,g_se,x_16

 权值从小到大排序   3 5 6 7 8 9 10 12 14 15

点                             1 3 3 5 3 5  1   4    3   6

点                             2 5 4 6 1 7  6   5    2   8

1.点1和点2不在同一颗树里,合并点1点2

2.点3和点5不在同一颗树里,合并点3点5

3.点3和点4不在同一颗树里,合并点3点4

4.点5和点6不在同一颗树里,合并点5点6

5.点1和点3不在同一颗树里,合并点1点3

6.点5和点7不在同一颗树里,合并点5点7

7.点1和点6在同一颗树里,不合并

8.点4和点5不在同一颗树里,不合并

9.点3和点2在同一颗树里,不合并

10.点6和点8不在同一颗树里,合并点6点8

已经选了七条边,结束算法

代码

洛谷P1194 买礼物

 

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
struct info{
	int s,e,w;
	bool operator < (info & a) const
	{
		return w < a.w;
	}
}node[250010];
int pre[510],v,n,c;
int Find(int a)
{
	if(pre[a] == a) return a;
	else return pre[a] = Find(pre[a]);
}
void Union(int a,int b)
{
	int _a = Find(a),_b = Find(b);
	if(a == b) return;
	else{
		pre[_a] = _b;
	}
}
void init()
{
	for(int i = 1;i < 510; i++)
		pre[i] = i;
}
void kruskal(int cnt)
{
	int t = 0,sum = 0;
	for(int i = 0;i < cnt; i++){
		if(Find(node[i].s) != Find(node[i].e)){
			t++;
			Union(node[i].s,node[i].e);
			sum += node[i].w;
		}
		if(t == n-1) break;
	}
	cout << sum + v;
}
int main()
{
	int cnt = 0;
	cin >> v >> n;
	for(int i = 1;i <= n; i++)
		for(int j = 1;j <=n; j++){
			cin >> c;
			if(i == j) c = INF;
			else if(c == 0 || c > v) c = v;
			node[cnt].s = i;node[cnt].e = j;node[cnt].w = c;
			cnt++;
		}
	sort(node,node+cnt-1);
	init();
	kruskal(cnt);
	return 0;
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值