简单并查集。要注意的是,像这种结点带有很多信息,要求对结点信息按连通分量进行汇总的并查集,可以不要在union操作里进行,而选择在进行完所有合并后,对所有结点遍历进行汇总。这样不容易出错。
#include <stdio.h>
#include <iostream>
#include <algorithm>
using namespace std ;
#define MAX 10000///最大范围
int f[MAX],vis[MAX]={0};///f用于记录并查集每个点的父亲 vis记录是否访问过
struct family///家族结构体
{
int id,people ;
double area,house ;//area是占地面积 house是房产套数
};
family person[MAX],*ans[MAX];//person记录相应id的家族信息,ans是个指针数组,记录答案
int ant = 0;//ans数组下标
bool cmp(family *a,family *b)///排序比较函数
{
if((a->area / a->people) == (b->area / b->people))
return a->id < b->id;
return (a->area / a->people) > (b->area / b->people);
}
void init()///初始化f
{
for(int i = 0;i < MAX;i ++)
f[i] = i;
}
int getf(int x)///get father
{
if(x != f[x])f[x] = getf(f[x]);
return f[x];
}
void marriage(int x , int y)///merge合并
{
int xx,yy;
xx = getf(x) ;
yy = getf(y) ;
if(xx != yy)
{
if(xx > yy)///方便找到最小id 让id小的当父亲那么找到的id与父亲相等的点最小id就是自己
{
f[xx] = yy;
}
else f[yy] = xx;
}
}
int main()
{
int n,id,mother,father,k,child;
cin>>n;
init();
for(int i = 0;i < n;i ++)
{
cin>>id>>father>>mother;
vis[id] = 1 ;
if(mother!=-1) {marriage(id,mother);vis[mother]=1;}///假如父亲访问过那么他肯定已经和id合并过 母亲也是
if(father!=-1) {marriage(id,father);vis[father]=1;}
cin>>k;
for(int j = 0;j < k;j ++)
{
cin>>child;
if(child!=-1)
{
marriage(id,child);
vis[child] = 1;
}
}
cin>>person[id].house>>person[id].area;///id作为下标方便寻找
}
for(int i = 0;i < MAX;i ++)
{
if(!vis[i])continue;
int f = getf(i);
if(f == i)
{
person[i].people ++;
ans[ant ++] = &person[i];
person[i].id = i;///需要注明
continue;
}
person[f].people ++;
person[f].house += person[i].house;
person[f].area += person[i].area;
}
sort(ans,ans + ant,cmp);
cout<<ant<<endl;
for(int i = 0;i < ant;i ++)
printf("%04d %d %.3f %.3f\n",ans[i]->id,ans[i]->people,ans[i]->house/ans[i]->people,ans[i]->area/ans[i]->people);
return 0 ;
}![