L2-007 家庭房产 (PTA)

题目

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

(题目链接: PTA | 程序设计类实验辅助教学平台)

思路

主要是并查集。可以先把所有人merge一遍,存一下每个人的编号,房产面积和房产套数,顺便把每个家庭的所有人存进一个数组里方便后面计算。然后我们可以遍历每个人的编号,查询其集团的父节点,用一个哈希表记录其父节点有没有被访问过,如果被访问过就跳过,没有被访问过就更新一下房产信息到父节点上。接着清空一下哈希表,去所有家庭的所有人当中去暴力查询是不是一个集团的,如果是就标记一下,塞到一个数组里用于答案输出。最后记得排序,家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。总结就是无敌史山大模拟。

代码

#include <bits/stdc++.h>

// from: cpp.json
#define INF 2e18
#define int long long
using namespace std;

struct DSU {
    vector<int> f, siz;
    
    DSU() {}
    DSU(int n) {
        init(n);
    }
    
    void init(int n) {
        f.resize(n);
        iota(f.begin(), f.end(), 0);
        siz.assign(n, 1);
    }
    
    int find(int x) {
        while (x != f[x]) {
            x = f[x] = f[f[x]];
        }
        return x;
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }

    bool merge(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return false;
        }
        siz[x] += siz[y];
        f[y] = x;
        return true;
    }
    
    int size(int x) {
        return siz[find(x)];
    }
};

struct Info {
    int min_num, tot_people;
    double avg_houses, avg_s;
    Info(int mn, int p, double a1, double a2) : min_num(mn), tot_people(p), avg_houses(a1), avg_s(a2) {}
};

void solve() {
    int n;
    cin >> n;

    DSU fam(10000);
    unordered_map<int, int> houses, sq;

    vector<int> rec;
    vector<pair<int, int>> temp;
    unordered_map<int, bool> seen;
    vector<int> a;

    for (int i = 0; i < n; i++) {
        int num, fa, mom, k;
        cin >> num >> fa >> mom >> k;
        a.push_back(num);
        rec.push_back(num);
        if (fa != -1) {
            fam.merge(num, fa);
            a.push_back(fa);
        }
        if (mom != -1) {
            fam.merge(num, mom);
            a.push_back(mom);
        }
        for (int j = 0; j < k; j++) {
            int x;
            cin >> x;
            if (x != -1) {
                fam.merge(num, x);
                a.push_back(x);
            }
        }
        int tot, s;
        cin >> tot >> s;
        temp.push_back({tot, s});
    }

    int cnt = 0;
    for (int i = 0; i < n; i++) {
        int fa = fam.find(rec[i]);
        if (seen[fa] == false) {
            seen[fa] = true;
            cnt++;
        } 
        houses[fa] += temp[i].first;
        sq[fa] += temp[i].second;
    }

    seen.clear();
    vector<Info> ans;

    unordered_map<int, bool> visited;

    for (int i = 0; i < n; i++) {
        if (visited[rec[i]]) continue;
        int fa = fam.find(rec[i]);
        visited[rec[i]] = true;
        if (seen[fa] == false) {
            seen[fa] = true;
        } else {
            continue;
        }
        int people = 1;
        int mn = fa;
        for (int x : a) {
            if (visited[x]) {
                continue;
            }
            if (fam.same(rec[i], x)) {
                people++;
                visited[x] = true;
                mn = min(mn, x);
            }
        }
        double a1 = (double) houses[fa] / (double) people;
        double a2 = (double) sq[fa] / (double) people;
        ans.push_back(Info(mn, people, a1, a2));
    }   

    cout << cnt << '\n';

    sort(ans.begin(), ans.end(), [&](Info& A, Info& B) {
        return A.avg_s > B.avg_s || (A.avg_s == B.avg_s && A.min_num < B.min_num);
    });

    for (auto it : ans) {
        cout << setw(4) << setfill('0') << it.min_num << ' ' << it.tot_people << ' ' << fixed << setprecision(3) << it.avg_houses << ' ' << fixed << setprecision(3) << it.avg_s << '\n'; 
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    solve();

    return 0;
}

### 家庭房产 PTA 测试点详细说明 在处理家庭房产相关的PTA测试点时,主要目标是对给定的数据进行分析和计算,最终按照特定规则输出每个家庭的相关统计数据。以下是详细的解析: #### 1. 输入数据结构 输入数据通常由两部分组成: - **家庭成员关系**:描述哪些人属于同一个家庭。这可以通过一系列整数表示,其中相同的编号代表同一家庭的成员[^1]。 - **个人名下房产信息**:对于每个人,提供其拥有的房产数量以及每套房产的面积。 #### 2. 输出要求 程序需输出以下内容: - 每个家庭的人口数。 - 每个家庭的人均房产套数(保留三位小数)。 - 每个家庭的人均房产面积(保留三位小数)。 - 结果应先按人均房产面积降序排列;如果两个家庭的人均面积相同,则按家庭中最小成员编号升序排列[^2]。 #### 3. 计算逻辑 为了完成上述任务,可以遵循如下算法设计原则: - 首先通过遍历输入的家庭成员列表来识别不同的家庭及其对应的成员集合。 - 对于每个家庭中的每位成员,累加他们所拥有房产的数量与总面积。 - 使用总人数除以总的房产数量得到人均房产套数,使用总人数除以总面积得到人均房产面积。 - 将所有家庭的结果存储在一个可排序的数据结构中,并依据指定条件对其进行排序。 下面是一个实现该功能的Python代码示例: ```python from collections import defaultdict def process_family_data(family_members, properties): family_dict = defaultdict(list) # Step to group members by their families. for idx, fam_id in enumerate(family_members): family_dict[fam_id].append(idx + 1) results = [] for fid, members in family_dict.items(): total_houses = 0 total_area = 0 for member in members: house_count, area_sum = properties.get(member, (0, 0)) total_houses += house_count total_area += area_sum population = len(members) avg_house = round(total_houses / population, 3) if population != 0 else 0 avg_area = round(total_area / population, 3) if population != 0 else 0 min_member = min(members) results.append((min_member, population, avg_house, avg_area)) # Sort the result based on average area and then minimum member id. sorted_results = sorted(results, key=lambda x: (-x[3], x[0])) return sorted_results family_members = [int(x) for x in input().split()] properties_input = {} n = int(input()) for _ in range(n): person, houses, areas = map(int, input().split()) properties_input[person] = (houses, areas * houses) output = process_family_data(family_members, properties_input) for res in output: print(*res) ``` 此代码实现了从读取输入到生成所需输出的过程。注意这里假设了某些形式化的输入方式作为例子展示用途,在实际应用中可能需要调整具体的输入方法以适应不同环境下的数据获取需求。 ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值