题目
给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。
(题目链接: 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;
}