最小生成树算法—kcruscal算法

1)  开始时,MST包含n个顶点,0条边;每个点都不连通,每个点为单独的一组;

2)  将边的权值按照从小到大排列,每次选取最小的权值边<u,v>加入到最小生成树中,加入的过程中要注意的地方是:

        不能产生环,那么如何判断呢?

         可以这样:在添加权值边<u,v>, 在添加之前,我们要判断u、v是否已经连通,若是,则不能添加这条边到MST中,反之,可以添加;

         那么,如何判断u、v两个顶点是否 已经连通呢?

         可以通过看u、v是否在相同的组中,相同组的顶点之间是连通的,不同组的顶点是不连通的。那么如何来描述组的这个概念呢?

        我们将所有的结点以整数表示,即对N个结点使用0—N-1的整数表示,开始的时候每个结点都是孤立的,即他们分别属于不同的组,可以用数组来表示这一 层关系,数组           的下标表示结点,相应的数组值表示该结点的组号;

         so,数组可以初始化为:

          for(int i=0;i<n;++i)

                 id[i] = i;

         这样,每当输入一个权值边<u、v>的时候,首先通过id数组判断u v是否在同一组中,若在,则舍弃<u、v>;反之,则将<u v>加入MST,并将他们的合并成一组,即将其中一个结点的组号换成另一个结点的组号;

         这样,对于每一条边,我们的算法可能要涉及到对数组的查找和修改,因此,我们可以考虑将结点和组的关系以树的形式表现出来。所以在数组中,我们可 以采用将结点以parent-link的方式组织起来,eg:  id[p] 的值就是p结点的父结点的序号,如果p是树根的话,id[p]的值就是p, 因此,经过若干次查找,一个结点总是能够找到它的根结点,然后就可以利用根结点的序号来表示组号,所以在处理一个pair的时候,将首先找到pair<u  v>中每一个结点的组号(它们所在树的根结点的序号),如果组号不相同 ,将pair计入MST,并且将u( or v)所在组的根结点的父节点设置为v (or u)所在组的根节点;相当于将一颗独立的树变成另一颗独立的树的子树。

const int MAX=100;
int parent[100];//parent[i]表示结点i的父节点(或者是爷爷结点)
int sz[100] = { 1 };//以结点i为根结点,其子节点有多少个(包括结点i)(树的大小)
struct node
{
	int begin;
	int end;
	int w;
}edge[MAX];

bool cmp(node a, node b)
{
	return a.w < b.w;
}
int find(int p)
{
	while (p != parent[p])
	{
		parent[p] = parent[parent[p]];
		p = p[parent];
	}
	return p;
}
void unionMerge(int begin, int end)
{
	int i = find(begin);
	int j = find(end);
	if (i == j)
		return;
	if (sz[i] < sz[j])
	{
		parent[i] = j;
		sz[j] += sz[i];
	}
	else
	{
		parent[j] = i;
		sz[i] += sz[j];
	}
	cout << "最小生成树中包含边:<"
		<< begin << "," << end << ">" << endl;
}
void kruscal(int m)
{
	for (int i = 0; i < m; ++i)
	{
		int u = edge[i].begin;
		int v = edge[i].end;
		unionMerge(u, v);
	}
}
void main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 0; i < MAX; ++i)
		parent[i] = i;
	for (int i = 0; i < m; ++i)
	{
		cin >> edge[i].begin >> edge[i].end >> edge[i].w;
	}
	sort(edge, edge + m, cmp);
	kruscal(m);
}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值