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;
}

本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值