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' 补齐。

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务