并查集的考察。
再合并的时候需要注意让最小的ID当作父亲结点,便于后面的输出。
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#define MAX 10000
using namespace std;
struct person{
int ID;
float m_estate;
float aera;
float sum;
person() { m_estate = 0; aera = 0; sum = 1; }
};
person p[MAX];
vector <person> family;//最终结果
set <int> s;//用来统计有资产的id
set <int> f;//用来统计家庭
int n,n_child;
void InitSet() {
for (int i = 0; i < MAX; i++) {
p[i].ID = i;
}
}
void CompressSet(int top ,int x) {
if (p[x].ID != top) {
CompressSet(top, p[x].ID);
p[x].ID = top;
}
}
int FindSet(int x) {
if (p[x].ID != x) {
int top = FindSet(p[x].ID);
CompressSet(top, x);
}
return p[x].ID;
}
void UnionSet(int x ,int y) {
int a = FindSet(x);
int b = FindSet(y);
if (a < b) {
p[b].ID = a;
p[a].sum += p[b].sum;//不要弄反了
}
else if(a > b) {
p[a].ID = b;
p[b].sum += p[a].sum;//不要弄反了
}
}
bool cmp(person p1, person p2) {
if (p1.aera > p2.aera)
return true;
else if (p1.aera == p2.aera && p1.ID < p2.ID)
return true;
return false;
}
int main() {
cin >> n;
InitSet();
int id, id_dad, id_mom, id_child;
for (int i = 0; i < n; i++) {
scanf("%d%d%d%d", &id, &id_dad, &id_mom, &n_child);
s.insert(id);
if(id_dad != -1)//父亲在
UnionSet(id, id_dad);
if(id_mom != -1)//母亲在
UnionSet(id, id_mom);
for (int j = 0; j < n_child; j++) {
scanf("%d", &id_child);
UnionSet(id, id_child);
}
scanf("%f%f", &p[id].m_estate, &p[id].aera);
}
set<int>::iterator it;
//累加结果
for (it = s.begin(); it != s.end(); it++) {
id = FindSet(*it);
if (id != *it) { //自己本身不累加
p[id].aera += p[*it].aera;
p[id].m_estate += p[*it].m_estate;
}
f.insert(id);
}
//统计家庭并计算
for (it = f.begin(); it != f.end(); it++) {
p[*it].aera /= p[*it].sum;
p[*it].m_estate /= p[*it].sum;
family.push_back(p[*it]);
}
sort(family.begin(), family.end(), cmp);
cout << family.size() << endl;
for (int i = 0; i < family.size(); i++) {
printf("%04d %.0f %.03f %.03f\n", family[i].ID, family[i].sum, family[i].m_estate, family[i].aera);
}
return 0;
}