这道题有点难度,不懂为啥正确率那么高。。。主要难在考差了并查集的同时,模拟还有点复杂。中间有几个地方要脑子清楚,比如一开始100010所有的父亲初始化为-1,表示没有这个元素。输入的时候,先要看看这个人的父亲是不是-1,如果是,那么父亲初始化为自己,再和别的元素合并,这个判断不能丢。
之前错就错在,这个人的父亲不是-1了,又输入的时候,我还把他的父亲变为自己,再去合并,这样子就错了。
之后就是遍历,父亲不是-1,说明有这个元素,可以寻找根,然后把这个家族的数据累加。接着再一次遍历,把各个家族的数据整理出来,按照题目要求排序输出即可。
第二次做,头文件只用了algorithm,代码也还算简短,感觉写的不错(只看了算法笔记,别的c++不会)
#include <bits/stdc++.h>
using namespace std;
struct student{
int idMin, num, sumEstate, sumArea;
}stu[100010], ans[100010];
int n, id, k, idFather, idMother, idChild, father[100010], estate[100010] = {}, area[100010] = {}, rec = 0;
bool cmp(student a, student b)
{
double t1 = a.sumArea * 1.0 / a.num, t2 = b.sumArea * 1.0 / b.num;
if(t1 != t2) return t1 > t2;
else return a.idMin < b.idMin;
}
int findfather(int x)
{
if(x == father[x]) return x;
else{
int f = findfather(father[x]);
father[x] = f;
return f;
}
}
void Union(int a, int b)
{
int f1 = findfather(a), f2 = findfather(b);
if(f1 != f2) father[f1] = f2;
}
void deal(int a, int b)
{
if(b != -1){
if(father[b] == -1) father[b] = b;
Union(a, b);
}
}
int main()
{
fill(father, father + 100010, -1);
for(int i = 0; i < 100010; i++){
stu[i].idMin = 100010;
stu[i].num = stu[i].sumEstate = stu[i].sumArea = 0;
}
scanf("%d", &n);
for(int i = 0; i < n; i++){
scanf("%d%d%d%d", &id, &idMother, &idFather, &k);
if(father[id] == -1) father[id] = id;
deal(id, idMother), deal(id, idFather);
for(int j = 0; j < k; j++){
scanf("%d", &idChild);
if(father[idChild] == -1) father[idChild] = idChild;
Union(id, idChild);
}
scanf("%d%d", &estate[id], &area[id]);
}
for(int i = 0; i < 100010; i++){
if(father[i] != -1){
int x = findfather(i);
stu[x].num++;
if(i < stu[x].idMin) stu[x].idMin = i;
stu[x].sumEstate += estate[i];
stu[x].sumArea += area[i];
}
}
for(int i = 0; i < 100010; i++){
if(stu[i].num) ans[rec++] = stu[i];
}
sort(ans, ans + rec, cmp);
printf("%d\n", rec);
for(int i = 0; i < rec; i++){
int x = ans[i].num;
printf("%04d %d %.3f %.3f\n", ans[i].idMin, x, ans[i].sumEstate * 1.0 / x, ans[i].sumArea * 1.0 / x);
}
return 0;
}