1114 Family Property

题目大意

给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。首先在第一行输出家庭个数(所有有亲属关系的人都属于同一个家庭)。随后按下列格式输出每个家庭的信息:家庭成员的最小编号 家庭人口数 人均房产套数 人均房产面积。其中人均值要求保留小数点后3位。家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。

思路解析

本题较好的做法是用并查集,在归并时,选节点小的作为新的父节点。用遍历也可以实现,但是时空复杂度会大大增加。
值得注意的是,不要在归并过程中做任何计算,单单归并就可以了。最后单独统计每个union的信息就可以,并不会浪费多少时间。

示例代码

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct node {
public:
	int id,count = 0, set = 0, area = 0;
};
vector<node> vec(10000);
int father[10000];
int find_father(int v) {
	int a = v;
	while (v != father[v]) {
		v = father[v];
	}
	while (a != father[a]) {
		int z = a;
		a = father[a];
		father[z] = v;
	}
	return v;
}
void Union(int x,int y) {
	int x_root = find_father(x);
	int y_root = find_father(y);
	if (x_root != y_root) {
		int temp = min(x_root, y_root);
		if (temp != y_root) {
			temp = x_root;
			x_root = y_root;
			y_root = temp;
		}
		father[x_root] = y_root;//保证id小的做老大		
	}
}
bool cmp(node n1, node n2) {
	double a1 = 1.0*n1.area / n1.count, a2 = 1.0*n2.area / n2.count;
	return a1 != a2 ? a1 > a2 :n1.id < n2.id;
}
int main() {
	int n;
	scanf("%d", &n);
	for (int i = 0; i < 10000; i++)
		father[i] = i;
	for (int i = 0; i < n; i++) {
		int a, b, c, d, e;
		scanf("%d %d %d %d", &a, &b, &c, &d);
		vector<int> temp(d);
		for (int j = 0; j < d; j++) 
			scanf("%d", &temp[j]);
		scanf("%d %d", &vec[a].set, &vec[a].area);
		if (b != -1) Union(a, b);
		if (c != -1) Union(a, c);
		for (int j = 0; j < temp.size(); j++)
			Union(a, temp[j]);
	}
	vector<node> res;
	vector<node> roots(10000);
	for (int i = 0; i < 10000; i++) {//找出所有老大
		int r = find_father(i);
		roots[r].id = r;
		roots[r].count++;
		roots[r].area += vec[i].area;
		roots[r].set += vec[i].set;
	}
	for (int i = 0; i < 10000; i++) {
		if (roots[i].area != 0)
			res.push_back(roots[i]);
	}
	sort(res.begin(), res.end(), cmp);
	printf("%d\n", res.size());
	for (int i = 0; i < res.size(); i++) {
		int id = res[i].id;
		printf("%04d %d %.3f %.3f\n", id, res[i].count, 1.0*res[i].set / res[i].count, 1.0*res[i].area / res[i].count);
	}
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值