
cpp
#include<bits/stdc++.h>
using namespace std;
const int N=9999;
int S[N]; // S[i]=1,编号为i的人是否存在
int s[N+10]; //并查集,查询编号为i的人家族中,编号最小的人的编号
using family = array<int, 4>; //编号、人数、总房产套数、总房产面积
using people = array<int, 3>; //编号、房产套数、房产面积
family f[N+10];
people p[N+10];
int find(int x){// 查
return s[x]==x?x:s[x]=find(s[x]);
}
void merge(int i, int j){// 并
i=find(i), j=find(j);
if(i<j) swap(i, j);
s[i]=j;
}
signed main(){
//初始化
for(int i=0;i<=N;i++)
s[i]=i, f[i][0]=i;
int n; cin>>n;
for(int i=1;i<=n;i++) {
int id,father,mother,k;
cin>>id>>father>>mother>>k;
if(father!=-1) merge(id, father);
if(mother!=-1) merge(id, mother);
S[id]=S[father]=S[mother]=1;
for(int j=1;j<=k;j++){
int x; cin>>x; S[x]=1;
merge(x, id);
}
int cnt, area; cin>>cnt>>area;
p[i]={id, cnt, area};
}
vector<int>indx; //所有家庭中成员(最小)编号索引
// 统计人数
for(int i=0;i<=N;i++) {
if(!S[i]) continue;
int target = find(i);
f[target][1]++;
if(i==target) indx.push_back(i);
}
// 统计房产
for(int i=1;i<=n;i++) {
auto [id, cnt, area] = p[i];
int target = find(id);
f[target][2]+=cnt;
f[target][3]+=area;
}
vector<family>ans;
for(auto it : indx)
ans.push_back(f[it]);
// 排序
sort(ans.begin(), ans.end(), [](family x, family y){
double avgx = (double)x[3]/x[1], avgy = (double)y[3]/y[1];
if(avgx!=avgy) return avgx>avgy; // 先按人均面积降序
return x[0]<y[0]; // 再按成员编号的升序
});
cout<<ans.size();
for(auto [id, nums, cnt, area]:ans){
cout<<endl;
cout<<setfill('0')<<setw(4)<<id<<' '<<nums<<' ';
cout<<fixed<<setprecision(3)<<(double)cnt/nums<<' ';
cout<<fixed<<setprecision(3)<<(double)area/nums;
}
}
考点:
并查集、模拟、排序
注意:
1."编号是每个人独有的一个4位数的编号",需要注意家庭成员的输出格式
cpp
cout<<setfill('0')<<setw(4)<<id<<' '<<nums<<' ';
2."人均值要求保留小数点后3位"
cpp
cout<<fixed<<setprecision(3)<<(double)cnt/nums<<' ';
cout<<fixed<<setprecision(3)<<(double)area/nums;
3.父母编号可能为-1,记得处理
4.并查集数组别忘了初始化
26/4/4