POJ 2377 最大生成树

问题描述: n个顶点,m条边,每条边有一个cost。 从m条边中选择若干条边使得n个顶点构成一颗树,要求cost的总和花费最大(最小)。

解决方案: kruskar算法生成最小生成树。关键点在于判断边的加入是否会引入环,环的检查使用并查集来实现,复杂度是O(lgN)。

算法的思想是贪心, 需要将输入的边按照cost从小到大排序,边的选择就是按照cost进行选择的。

#include<iostream>
#include<algorithm>
#include<fstream>

using namespace std;

//#define DEBUG

struct edge
{
	int u;
	int v;
	int w;
};
bool cmp(const edge &a, const edge &b)
{
	return a.w > b.w;
}
static struct edge edges[20000];
static int p[1001];
static int num[1001];
int findset(int x) /* 压缩路径 */
{
	if (x != p[x])
		p[x] = findset(p[x]);
	return p[x];
}

int unionset(int s1, int s2)  /* 按照数量合并 */
{
	if (s1 == s2)	return -1;
	if (num[s1] > num[s2])
	{
		p[s2] = s1; num[s2] = 0;
	}
	else
	{
		p[s1] = s2; num[s1] = 0;
	}
	return 0;
}

int main()
{
#ifdef DEBUG
	fstream cin("G:\\book\\algorithms\\acm\\Debug\\dat.txt");
#endif
	int n, m;
	cin >> n >> m;
	int i;
	for (i = 0; i < m; i++)
	{
		cin >> edges[i].u >> edges[i].v >> edges[i].w;
	}
	sort(edges, edges + m, cmp);/* 降序排列 贪心*/
	for (i = 1; i <= n; i++)
	{
		p[i] = i;	num[i] = 1;
	}
	int cost = 0;
	int trees = n;
	for (i = 0; i < m; i++)
	{
		int pu, pv;
		pu = findset(edges[i].u);
		pv = findset(edges[i].v);
		if (pv != pu) /* the edge connect different trees */
		{
			unionset(pv,pu);
			cost += edges[i].w;
			trees--;
		}
	}
	if (trees > 1)
		cout << -1 << "\n";
	else 
		cout << cost << "\n"; 
	return 0;
}

使用最小生成树算法,理论分析见算法导论的23.2小节。 

基本的算法思想是贪心算法。对输入的边按照权重进行排序后依次处理,根据排序的方式决定是最大生成树还是最小生成树。

成树的过程中防止生成环, 采用并查集的方式进行检测。可以看出使用并查集后算法的过程就很简单了。复杂度是和边的数目有关的,

是否能够成树,即是否最终能够得到一个联通图,采用变量进行检测即可。

Kruskal算法对边进行操作,初始状态是n棵树构成的森林,通过边将各个树联通,构成一个无环的联通图

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值