POJ 2377 Bad Cowtractors(并查集+贪心)

题目:

有N个点和M条边,每条边都有一个花费cost。求出一些边使得:

1 这些边的总花费最大。

2 所有点连通,即任意节点都可以到达所有节点。

3 不存在环路。

如果不能连通所有点,则输出-1

解题思路:

该题类似于最小生成树。可使用并查集和贪心算法解决。

1 将所有边按cost从大到小排序。

2 将N个点初始化为N个并查集。

3 从左到右遍历边数组,合并当前边连接的两个节点所在的并查集,如果两个节点位于同一个集合则不合并,如果发生了合并,将该边的花费累加到总花费中。如果合并后的集合节点数目达到了N,则完成了所有点的连通,循环结束。

4 如果所有节点都位于同一个并查集,则输出最大花费,否则输出-1。

代码:

#include<stdio.h>

typedef struct
{
	int a,b; //节点a和b
	int cost; //花费 
} route;

int father[1001];
int rank[1001];
int mem[1001];
route edges[20000];

int cmp(const void *a, const void *b)
{
	return ((route*)b)->cost - ((route*)a)->cost;
}

void make_set(int x)
{
	father[x]=x;
	rank[x]=0;
	mem[x]=1;
}

//查找x所在并查集的根节点编号 
int find_set(int x)
{
	if(father[x] != x) father[x]=find_set(father[x]);
	return father[x];
}

//合并a节点和b节点所在的并查集,返回合并后集合的节点数,属于同一个集合返回0 
int union_set(int a, int b)
{
	int result;
	a=find_set(a);
	b=find_set(b);
	if(a==b) return 0;
	if(rank[a] < rank[b])
	{
		father[a]=b;
		mem[b] += mem[a];
		result=mem[b];
	}
	else
	{
		if(rank[a]==rank[b]) rank[a]++;
		father[b]=a;
		mem[a]+=mem[b];
		result=mem[a];
	}
	return result;
}


int main()
{
	int n,m,i,result,ans=0;
	scanf("%d%d", &n, &m);
	for(i=0; i<m; i++) scanf("%d%d%d", &edges[i].a, &edges[i].b, &edges[i].cost);
	
	//初始化并查集
	for(i=1; i<=n; i++) make_set(i);
	
	//对边排序
	qsort(edges, m, sizeof(route), cmp);
	
	for(i=0; i<m; i++)
	{
		result=union_set(edges[i].a, edges[i].b);
		if(result) ans += edges[i].cost;
		if(result == n) break; //已经连接所有节点 
	}
	if(result==n)
 	 printf("%d\n", ans);
 	else printf("%d\n", -1);
	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值