给定每个人的家庭成员以及他/她自己名字下的房产信息,我们需要知道每个家庭的规模,以及他们房产的平均面积和套数。
输入第一行给出一个正整数 N。接下来 N 行,每行以$ID\ Father\ Mother\ k\ Child_1\cdots\ Child_k\ M_{estate}\ Area$格式提供拥有财产的人的信息。其中,ID 是每个人的唯一 4 位标识号;父亲和母亲是此人父母的 ID(如果父母去世,则对应值为-1)k 是此人的孩子数;$Child_i$是他/她孩子的 ID;$M_{estate}$是他/她名字下的房产总数;Area 是他/她的房产总面积。
首先在一行中打印家庭数量(将直接或间接相关的所有人都视为同一家庭)。然后以$ID\ M\ AVG_{sets}\ AVG_{area}$格式输出家庭信息。其中 ID 是家庭成员中最小的 ID;M 是家庭成员总数;$AVG_{sets}$是其房地产的平均套数;$AVG_{area}$是平均面积。平均值必须精确到小数点后 3 位。按平均面积降序的顺序输出家庭的相关信息,如果平均面积相同,则按 ID 的升序输出所有家庭的相关信息。
使用并查集,由于成员 ID 是 4 位数字,并查集数组需开到${10}^4$。额外开辟两个数组 sets、area,分别存储一个家庭名下的房产总数和总面积。在读取输入数据时,用一个 unordered_set<gg> us
存储所有输入的人员编号。合并一行输入中的所有出现的 ID,并将成员的房产信息读取到 sets 和 area 中。注意,由于要求输出家庭中最小的 ID,可以在合并集合的时候,将根结点编号大的集合合并到跟结点编号小的集合,这样可以保证根结点的编号就是这个家庭中的最小编号。
定义一个 vector 类型变量 roots 存储所有家庭的根结点。遍历 us,将所有根结点编号记录到 roots 中,并将所有成员的房产信息累加到根结点的房产信息中。将 roots 按要求排序并输出。
#include <bits/stdc++.h>
using namespace std;
using gg = long long;
const gg MAX = 1e4 + 5;
vector<gg> ufs(MAX), num(MAX, 1), sets(MAX), area(MAX);
void init() { iota(ufs.begin(), ufs.end(), 0); }
gg findRoot(gg x) { return ufs[x] == x ? x : ufs[x] = findRoot(ufs[x]); }
void unionSets(gg a, gg b) {
gg ra = findRoot(a), rb = findRoot(b);
ufs[max(ra, rb)] = min(ra, rb); //合并到根结点编号小的集合
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
init();
gg ni;
cin >> ni;
unordered_set<gg> us; //存储所有输入的人员编号
while (ni--) {
gg id, fi, mi, ki, ai;
cin >> id >> fi >> mi >> ki;
us.insert(id);
if (fi != -1) {
us.insert(fi);
unionSets(id, fi);
}
if (mi != -1) {
us.insert(mi);
unionSets(id, mi);
}
while (ki--) {
cin >> ai;
us.insert(ai);
unionSets(id, ai);
}
cin >> sets[id] >> area[id]; //房产总数存储在sets中,面积存储在area中
}
vector<gg> roots; //存储所有集合的根结点
for (auto& i : us) {
gg r = findRoot(i); //根结点
if (find(roots.begin(), roots.end(), r) == roots.end()) {
roots.push_back(r);
}
if (i != r) { //如果i不是跟结点,将i的相关信息累加到跟结点r中
num[r]++;
sets[r] += sets[i];
area[r] += area[i];
}
}
sort(roots.begin(), roots.end(), [](int a, int b) {
return make_pair(area[b] * 1.0 / num[b], a) <
make_pair(area[a] * 1.0 / num[a], b);
}); //排序
cout << fixed << setprecision(3) << setfill('0') << roots.size() << "\n";
for (gg i : roots) {
cout << setw(4) << i << " " << num[i] << " " << sets[i] * 1.0 / num[i]
<< " " << area[i] * 1.0 / num[i] << "\n";
}
return 0;
}