题目详情 - L2-007 家庭房产 (25 分) (pintia.cn)
并查集
思路:记录家庭人数、房产数量和房产面积的思想跟算连通块一样(记得初始化),新的结点并入集合时同时该结点的属性值加入祖宗结点上去(将最小编号设为祖宗),最后轮询一遍获得祖宗(f[x] = x 点)的数量就是家庭的数量。然后结构体排序输出即可。
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 10010;
//cnt 房产数, pn家庭人数
int f[N],cnt[N],area[N],pn[N];
vector<int> child(N);
struct Node{
int id,pn;
double avlc,avla; //人均房产数 人均面积
bool operator<(const Node &t) const{
if(avla != t.avla) return avla > t.avla;
return id < t.id;
}
};
int getf(int x){
if(x == f[x]) return x;
else return f[x] = getf(f[x]);
}
void merge(int a,int b){
int ta = getf(a);
int tb = getf(b);
if(ta != tb){
if(ta > tb) swap(ta,tb);
f[tb] = ta;
cnt[ta] += cnt[tb];
area[ta] += area[tb];
pn[ta] += pn[tb];
}
}
void init(int x){
pn[x] = 1;
f[x] = x;
}
int main(){
int n;
cin>>n;
memset(f,-1,sizeof f);
memset(cnt,0,sizeof cnt);
memset(area,0,sizeof area);
for(int i = 0; i < n; i++){
int num,father,mother,k;
cin>>num>>father>>mother>>k;
for(int j = 0; j < k; j++){
cin>>child[j];
if(f[child[j]] == -1) init(child[j]);
}
int fc,zarea;
cin>>fc>>zarea;
if(f[num] == -1) init(num);
cnt[getf(num)] += fc;
area[getf(num)] += zarea;
if(father != -1) {
if(f[father] == -1) init(father);
merge(num,father);
}
if(mother != -1) {
if(f[mother] == -1) init(mother);
merge(num,mother);
}
for(int j = 0; j < k; j++) merge(num,child[j]);
}
vector<Node> ans;
for(int i = 0; i < N; i++)
if(f[i] == i)
ans.push_back({i,pn[i],1.0*cnt[i]/pn[i],1.0*area[i]/pn[i]});
sort(ans.begin(),ans.end());
cout<<ans.size()<<'\n';
for(int i = 0; i < ans.size(); i++)
printf("%04d %d %.3lf %.3lf\n",ans[i].id,ans[i].pn,ans[i].avlc,ans[i].avla);
return 0;
}
图的遍历
L2-007 家庭房产 (25 分)_再敲一行就去睡的博客-优快云博客
这个可能会更好写一些。