给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。

输入格式:

输入第一行给出一个正整数N(≤1000),随后N行,每行按下列格式给出一个人的房产:

1
编号 父 母 k 孩子1 ... 孩子k 房产套数 总面积

其中编号是每个人独有的一个4位数的编号;分别是该编号对应的这个人的父母的编号(如果已经过世,则显示-1);k(0≤k≤5)是该人的子女的个数;孩子i是其子女的编号。

输出格式:

首先在第一行输出家庭个数(所有有亲属关系的人都属于同一个家庭)。随后按下列格式输出每个家庭的信息:

1
家庭成员的最小编号 家庭人口数 人均房产套数 人均房产面积

其中人均值要求保留小数点后3位。家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。

输入样例:

1
2
3
4
5
6
7
8
9
10
11
10
6666 5551 5552 1 7777 1 100
1234 5678 9012 1 0002 2 300
8888 -1 -1 0 1 1000
2468 0001 0004 1 2222 1 500
7777 6666 -1 0 2 300
3721 -1 -1 1 2333 2 150
9012 -1 -1 3 1236 1235 1234 1 100
1235 5678 9012 0 1 50
2222 1236 2468 2 6661 6662 1 300
2333 -1 3721 3 6661 6662 6663 1 100

输出样例:

1
2
3
4
3
8888 1 1.000 1000.000
0001 15 0.600 100.000
5551 4 0.750 100.000

思路:

题目要求做的事情很多,理清一下要求:

  • 根据输入确定有多少家庭
  • 计算每个家庭中成员的最小编号(不是辈分最小的成员的编号)
  • 计算每个家庭的信息,即家庭人数、所拥有的房屋总数、房屋总面积

可使用并查集以家庭为树,确定每个家庭的成员有哪些

然后,遍历并查集,确定以上要求中的数值

如下为总体步骤:

  1. 建立两个结构体,一个代表个人信息,一个代表家庭信息
  2. 输入过程中,合并结点,建立并查集
  3. 遍历并查集,确定有多少家庭,和所有个人编号所在的家庭
  4. 再次遍历并查集,将每个人的房产信息加入其所在家庭中
  5. 排序输出

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;
constexpr int MAX_SIZE = 10001;

struct Person {
int id;//此人编号
int root;//此人所在家庭并查集的根
int house;//拥有房子数
double area;//拥有面积数
};

struct Family {
int min_id;//该家庭成员最小编号
int p_sum;//该家庭总人口
int house_sum;//该家庭总房屋
double area_sum;//该家庭总房屋面积
};

Person f[MAX_SIZE];//以家庭为树合并,全局变量,成员初始值均为0
bool book[MAX_SIZE];//某编号是否存在

int my_query(const int &i) {
return f[i].root = f[i].root == i ? i : my_query(f[i].root);
}

void my_merge(const int &a, const int &b) {
if (a == -1 || b == -1) {
return;
}
int t1 = my_query(f[a].root);
int t2 = my_query(f[b].root);
f[t2].root = t1;
}

int cmp(const Family& a, const Family& b) {//排序函数
if (a.area_sum / a.p_sum != b.area_sum / b.p_sum) {
return a.area_sum / a.p_sum > b.area_sum / b.p_sum;
} else {
return a.min_id < b.min_id;
}
}

int main() {
int n;
scanf("%d", &n);
for (int i = 0; i < MAX_SIZE; i++) {//初始化并查集
f[i].root = i;
f[i].id = i;
}
for (int i = 1; i <= n; i++) {
int id, mom, dad, k;
scanf("%d %d %d %d", &id, &mom, &dad, &k);
book[id] = 1;
book[mom] = 1;
book[dad] = 1;
my_merge(id, mom);
my_merge(id, dad);
while(k--) {
int child;
scanf("%d", &child);
book[child] = 1;
my_merge(id, child);
}
scanf("%d %lf", &f[id].house, &f[id].area);
}
vector<Family> ret;
int h_index[MAX_SIZE] {0};//记录家庭在ret数组中的索引
int cot = 0;
for (int i = 0; i < MAX_SIZE; i++) {//第一次遍历并查集,确定有多少家庭
if (!book[i]) {//此编号不存在
continue;
}
f[i].root = my_query(f[i].root);
if (f[i].root == i) {//i此人代表了一个家庭
ret.push_back({ i, 0, 0, 0 });
h_index[i] = cot++;//记录该家庭在ret数组中的位置
}
}
for (int i = 0; i < MAX_SIZE; i++) {//第二次遍历并查集,确定每个家庭的房产信息
if (!book[i]) {//此编号不存在
continue;
}
int index = h_index[f[i].root];//该编号所在家庭在ret数组中的索引
if (f[i].id < ret[index].min_id) {
ret[index].min_id = f[i].id;//更新最小编号
}
ret[index].p_sum++;//更新家庭信息
ret[index].house_sum += f[i].house;
ret[index].area_sum += f[i].area;
}
printf("%llu\n", ret.size());//家庭数
sort(ret.begin(), ret.end(), cmp);//排序
for(Family it : ret) {//输出
printf("%04d %d %.3lf %.3lf\n",
it.min_id, it.p_sum, (double)it.house_sum / it.p_sum, it.area_sum / (double)it.p_sum);
}
return 0;
}