最大生成树&并查集练习

征兵

【题目描述】:

一个国王,他拥有一个国家。最近他因为国库里钱太多了,闲着蛋疼要征集一只部队要保卫国家。他选定了N个女兵和M个男兵,但事实上每征集一个兵他就要花10000RMB,即使国库里钱再多也伤不起啊。他发现,某男兵和某女兵之间有某种关系(往正常方面想,一共R种关系),这种关系可以使KING少花一些钱就可以征集到兵,不过国王也知道,在征兵的时候,每一个兵只能使用一种关系来少花钱。这时国王向你求助,问他最少要花多少的钱。

【输入描述】:

第一行:T,一共T组数据。

接下来T组数据,

第一行包括N,M,R

接下来的R行 包括Xi,Yi,Vi 表示如果招了第Xi个女兵,再招第Yi个男兵能省Vi元(同样表示如果招了第Yi个男兵,再招第Xi个女兵能也省Vi元)

【输出描述】:

共T行,表示每组数据的最终花费是多少(因为国库里的钱只有2^31-1,所以保证最终花费在maxlongint范围内)

【样例输入】:

2
5 5 8
4 3 6831
1 3 4583
0 0 6592
0 1 3063
3 3 4975
1 3 2049
4 2 2104
2 2 781
5 5 10
2 4 9820
3 2 6236
3 1 8864
2 4 8326
2 0 5156
2 0 1463
4 1 2439
0 4 4373
3 4 8889
2 4 3133

【样例输出】:

71071
54223

【时间限制、数据范围及描述】:

时间:1s 空间:128M

T<=5 ,m,n<=10000,r<=50000,Xi<=m,Yi<=n,Vi<=10000,结果<=2^31-1


通过题目描述我们可以知道,要想使最终的答案最小,就必须让男女之间的关系所减去的钱数最大。那么在这里我们就要使用最大生成树算法了(Kruskal)。与最小生成树不同的是,我们先要对关系进行一次降序排序,然后通过并查集判断男女之间是否有了间接或直接的关系,若没有则加上省去的钱并将这个男兵和女兵放到一个集合里。

AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct node{
	int u,v,w;
}t[50005];
int f[20005];
int find(int x){
	if(f[x]==x)return f[x];
	else return f[x]=find(f[x]);
}
void unin(int x,int y){
	f[x]=y;
}
bool cmp(node x,node y){
	return x.w>y.w;
}
void work(){
	int n,m,r,ans=0,fx,fy;
	scanf("%d%d%d",&n,&m,&r);
	for(int i=0;i<=n+m;i++){
		f[i]=i;
	}
	for(int i=0;i<r;i++){
		scanf("%d%d%d",&t[i].u,&t[i].v,&t[i].w);
		t[i].v+=n+1;
	}
	sort(t,t+r,cmp);
	for(int i=0;i<r;i++){
		fx=find(t[i].u);fy=find(t[i].v);
		if(fx!=fy){
			ans+=t[i].w;
			unin(fx,fy);
		}
	}
	printf("%d\n",(n+m)*10000-ans);
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		work();
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值