L2-007 家庭房产
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
#include <iomanip>
using namespace std;
const int MAXN = 10000; // 最大编号范围,编号是4位数,范围是0000-9999
struct Person {
int id; // 个人编号
int father; // 父亲编号
int mother; // 母亲编号
vector<int> children; // 子女编号列表
int numHouses; // 房产套数
double area; // 房产总面积
};
struct Family {
int minId; // 家庭成员的最小编号
int size; // 家庭人口数
double totalHouses; // 家庭总房产套数
double totalArea; // 家庭总房产面积
};
int parent[MAXN]; // 并查集的父节点数组
map<int, Person> persons; // 存储所有人的信息,键为编号
map<int, bool> exists; // 记录哪些编号存在
// 并查集的查找函数,带路径压缩
int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]); // 路径压缩
}
return parent[x];
}
// 并查集的合并函数
void unionSets(int x, int y) {
if (x == -1 || y == -1) return; // 忽略无效编号(如-1)
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
parent[rootX] = rootY; // 合并两个集合
}
}
// 比较函数,用于家庭排序
bool compareFamilies(const Family& a, const Family& b) {
double avgAreaA = a.totalArea / a.size; // 家庭A的人均面积
double avgAreaB = b.totalArea / b.size; // 家庭B的人均面积
if (avgAreaA != avgAreaB) {
return avgAreaA > avgAreaB; // 按人均面积降序
}
return a.minId < b.minId; // 如果人均面积相同,按最小编号升序
}
int main() {
int N;
cin >> N; // 输入人数
// 初始化并查集
for (int i = 0; i < MAXN; i++) {
parent[i] = i; // 每个节点的父节点初始化为自己
}
// 输入数据
for (int i = 0; i < N; i++) {
Person p;
cin >> p.id >> p.father >> p.mother; // 输入编号、父亲编号、母亲编号
int k;
cin >> k; // 输入子女数量
p.children.resize(k);
for (int j = 0; j < k; j++) {
cin >> p.children[j]; // 输入每个子女的编号
}
cin >> p.numHouses >> p.area; // 输入房产套数和总面积
persons[p.id] = p; // 将个人信息存入map
exists[p.id] = true; // 标记该编号存在
if (p.father != -1) exists[p.father] = true; // 标记父亲编号存在
if (p.mother != -1) exists[p.mother] = true; // 标记母亲编号存在
for (int child : p.children) exists[child] = true; // 标记子女编号存在
// 合并家庭成员
unionSets(p.id, p.father); // 合并本人和父亲
unionSets(p.id, p.mother); // 合并本人和母亲
for (int child : p.children) {
unionSets(p.id, child); // 合并本人和子女
}
}
// 统计家庭信息
map<int, Family> families;
for (auto& pair : exists) {
int id = pair.first; // 当前编号
int root = find(id); // 找到该编号的根节点(家庭代表)
if (families.find(root) == families.end()) {
// 如果该家庭尚未被统计,初始化家庭信息
families[root] = {id, 0, 0, 0};
}
families[root].size++; // 家庭人口数加1
if (id < families[root].minId) {
families[root].minId = id; // 更新家庭成员的最小编号
}
if (persons.find(id) != persons.end()) {
// 如果该编号有房产信息,累加到家庭总房产套数和总面积
families[root].totalHouses += persons[id].numHouses;
families[root].totalArea += persons[id].area;
}
}
// 转换为结果数组
vector<Family> result;
for (auto& pair : families) {
result.push_back(pair.second); // 将家庭信息存入结果数组
}
// 排序
sort(result.begin(), result.end(), compareFamilies); // 按人均面积降序排序
// 输出结果
cout << result.size() << endl; // 输出家庭数量
for (const Family& f : result) {
// 输出家庭成员的最小编号、人口数、人均房产套数、人均房产面积
cout << setw(4) << setfill('0') << f.minId << " "
<< f.size << " "
<< fixed << setprecision(3) << f.totalHouses / f.size << " "
<< f.totalArea / f.size << endl;
}
return 0;
}
1. 代码解析
- families:一个容器(如 map 或 unordered_map),存储键值对。
- root:要查找的键。
- families.find(root):
在 families 中查找键 root。
如果找到,返回指向该键值对的迭代器。
如果未找到,返回 families.end()。
- families.end():
返回指向容器末尾的迭代器,表示查找失败。
2.for (auto& pair : exists) 是 C++ 中的一种 范围 for 循环,用于遍历 exists 中的所有元素。以下是详细说明:
- exists:一个容器(如 map 或 unordered_map),存储键值对。
- auto& pair:
- auto:自动推导 pair 的类型。
- &:表示 pair 是引用,可以直接修改 exists 中的元素。
- pair:临时变量,表示 exists 中的每个键值对。
- exists 的类型
假设 exists 是一个 map<int, bool>,那么:
- pair 的类型:std::pair<const int, bool>&。
- pair.first:键(int 类型),表示编号。
- pair.second:值(bool 类型),表示编号是否存在。
3.p.children.resize(k); 是 C++ 中的一条语句,用于调整 p.children 容器的大小。以下是详细说明:
- 将 p.children 容器的大小调整为 k。
- 如果 k 大于当前大小,则新增元素会被默认初始化。
- 如果 k 小于当前大小,则多余的元素会被删除。
4.setw(4):
设置输出字段的宽度为 4。
如果输出的数据不足 4 位,则用填充字符补齐。
setfill('0'):
设置填充字符为 '0'。
如果输出的数据不足 4 位,则用 '0' 补齐。
查看7道真题和解析