PAT A1114 Family Property [并查集]
题目描述
链接
给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。首先在第一行输出家庭个数(所有有亲属关系的人都属于同一个家庭)。随后按下列格式输出每个家庭的信息:家庭成员的最小编号 家庭人口数 人均房产套数 人均房产面积。其中人均值要求保留小数点后3位。家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。
分析
- 维护的是亲属关系,只要是有亲属关系,则属于这个集合,不用管这是是父母还是孩子,反正有亲属关系就好了
- \(fa[i]=i\) 就算事先还没有明确元素个数,也可以先初始化了再说,也就是循环到\(maxn\)
- 然后输入一个亲属结点(父母孩子),就执行\(merge(id, xxx)\)
- 用\(data\)结构体数组接收数据,同时进行\(merge\)操作
- 用\(ans\)结构体数组统计信息,里面有很多坑,看代码吧
- 因为之前是循环到\(maxn\),所以用了\(vis\)数组来标记有效结点
- 同时加\(flag\)变量标记根结点
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 1e5;
int fa[maxn];
bool vis[maxn];
int n,k,cnt;
struct Data{
int id, fid, mid, num, area, cid[10];
}data[1005];
struct node {
int id, cnt;
double num, area;
bool flag;
}ans[maxn];
int find(int x){
int r = x;
while(x != fa[x]) x = fa[x];
while(r != fa[r]){
int t = r;
r = fa[r];
fa[t] = x;
}
return x;
}
void merge(int x, int y){
int fx = find(x);
int fy = find(y);
if(fx!=fy) fa[max(fx,fy)] = min(fx,fy); //较小编号的作为祖先
}
int cmp(node a, node b) {
if(a.area != b.area) return a.area > b.area;
return a.id < b.id;
}
int main() {
int n, k, cnt = 0;
scanf("%d", &n);
for(int i = 0; i < maxn; i++) fa[i] = i; //当结点数未定时也可以初始化
//用data结构体保存读入的数据,注意data的大小只有n,不是maxn
for(int i = 0; i < n; i++) {
scanf("%d %d %d %d", &data[i].id, &data[i].fid, &data[i].mid, &k);
vis[data[i].id] = true;
if(data[i].fid != -1) {
vis[data[i].fid] = true;
merge(data[i].fid, data[i].id);
}
if(data[i].mid != -1) {
vis[data[i].mid] = true;
merge(data[i].mid, data[i].id);
}
for(int j = 0; j < k; j++) {
scanf("%d", &data[i].cid[j]);
vis[data[i].cid[j]] = true;
merge(data[i].cid[j], data[i].id);
}
scanf("%d %d", &data[i].num, &data[i].area);
}
//用ans结构体统计信息,只保存根节点
for(int i = 0; i < n; i++) {
int id = find(data[i].id);
ans[id].id = id;
ans[id].num += data[i].num;
ans[id].area += data[i].area;
ans[id].flag = true;
}
//统计集合元素个数和根结点数目
for(int i = 0; i < maxn; i++) {
if(vis[i])
ans[find(i)].cnt++;
if(ans[i].flag)
cnt++;
}
//计算平均
for(int i = 0; i < maxn; i++) {
if(ans[i].flag) {
ans[i].num = (double)(ans[i].num * 1.0 / ans[i].cnt);
ans[i].area = (double)(ans[i].area * 1.0 / ans[i].cnt);
}
}
sort(ans, ans + maxn, cmp);
printf("%d\n", cnt);
for(int i = 0; i < cnt; i++)
printf("%04d %d %.3f %.3f\n", ans[i].id, ans[i].cnt, ans[i].num, ans[i].area);
return 0;
}