![]() ![]() |
题目大意
给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。首先在第一行输出家庭个数(所有有亲属关系的人都属于同一个家庭)。随后按下列格式输出每个家庭的信息:家庭成员的最小编号 家庭人口数 人均房产套数 人均房产面积。其中人均值要求保留小数点后3位。家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。思路解析
本题较好的做法是用并查集,在归并时,选节点小的作为新的父节点。用遍历也可以实现,但是时空复杂度会大大增加。值得注意的是,不要在归并过程中做任何计算,单单归并就可以了。最后单独统计每个union的信息就可以,并不会浪费多少时间。
示例代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct node {
public:
int id,count = 0, set = 0, area = 0;
};
vector<node> vec(10000);
int father[10000];
int find_father(int v) {
int a = v;
while (v != father[v]) {
v = father[v];
}
while (a != father[a]) {
int z = a;
a = father[a];
father[z] = v;
}
return v;
}
void Union(int x,int y) {
int x_root = find_father(x);
int y_root = find_father(y);
if (x_root != y_root) {
int temp = min(x_root, y_root);
if (temp != y_root) {
temp = x_root;
x_root = y_root;
y_root = temp;
}
father[x_root] = y_root;//保证id小的做老大
}
}
bool cmp(node n1, node n2) {
double a1 = 1.0*n1.area / n1.count, a2 = 1.0*n2.area / n2.count;
return a1 != a2 ? a1 > a2 :n1.id < n2.id;
}
int main() {
int n;
scanf("%d", &n);
for (int i = 0; i < 10000; i++)
father[i] = i;
for (int i = 0; i < n; i++) {
int a, b, c, d, e;
scanf("%d %d %d %d", &a, &b, &c, &d);
vector<int> temp(d);
for (int j = 0; j < d; j++)
scanf("%d", &temp[j]);
scanf("%d %d", &vec[a].set, &vec[a].area);
if (b != -1) Union(a, b);
if (c != -1) Union(a, c);
for (int j = 0; j < temp.size(); j++)
Union(a, temp[j]);
}
vector<node> res;
vector<node> roots(10000);
for (int i = 0; i < 10000; i++) {//找出所有老大
int r = find_father(i);
roots[r].id = r;
roots[r].count++;
roots[r].area += vec[i].area;
roots[r].set += vec[i].set;
}
for (int i = 0; i < 10000; i++) {
if (roots[i].area != 0)
res.push_back(roots[i]);
}
sort(res.begin(), res.end(), cmp);
printf("%d\n", res.size());
for (int i = 0; i < res.size(); i++) {
int id = res[i].id;
printf("%04d %d %.3f %.3f\n", id, res[i].count, 1.0*res[i].set / res[i].count, 1.0*res[i].area / res[i].count);
}
return 0;
}