团体程序设计天梯赛-练习集
L2-007. 家庭房产
https://www.patest.cn/contests/gplt/L2-007
先进行并查集,在并集时将信息赋值给最小的编号,同时记录所有的第一个编号,之后用set把所有第一个的编号的根放入set,直接输出。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
using namespace std;
void unite(int x, int y);
const int maxn = 10005;
int par[maxn];
int ran[maxn];
struct Size {
int g;
double area;
}siz[maxn];
struct Ans {
int name;
double g;
double area;
bool operator<(const Ans &t1) const {
if (area != t1.area) {
return (area > t1.area);
}
else if (ran[name] != ran[t1.name]) {
return (ran[name] > ran[t1.name]);
}
else {
return (name < t1.name);
}
}
}ans;
int k;
void update(int a) {
int b;
scanf("%d", &b);
if (b == -1) {
return;
}
else {
unite(a, b);
}
}
void init(int n) {
for (int i = 0; i <= n; i++) {
par[i] = i;
ran[i] = 1;
}
}
int find(int x) {
int r = x;
while (r != par[r])
r = par[r];
int i = x, j;
while (par[i] != r)
{
j = par[i];
par[i] = r;
i = j;
}
return r;
}
void unite(int x, int y) {
x = find(x);
y = find(y);
if (x == y) return;
if (x > y) {
par[x] = y;
ran[y] += ran[x];
siz[y].g += siz[x].g;
siz[y].area += siz[x].area;
}
else {
par[y] = x;
ran[x] += ran[y];
siz[x].g += siz[y].g;
siz[x].area += siz[y].area;
}
}
set<Ans>s;
int main() {
int N;
while (scanf("%d", &N) != EOF) {
if (N == 0) {
continue;
}
if (s.size()) {
s.clear();
}
init(10000);
k = 0;
int a[1024];
memset(siz, 0, sizeof(siz));
for (int i = 0; i < N; i++) {
int z;
scanf("%d", &a[i]);
update(a[i]);
update(a[i]);
scanf("%d", &z);
for (int j = 0; j < z; j++) {
update(a[i]);
}
int m;
double ar;
scanf("%d%lf", &m, &ar);
siz[find(a[i])].g += m;
siz[find(a[i])].area += ar;
}
for (int i = 0; i < N; i++) {
ans.name = find(a[i]);
ans.g = (double)siz[ans.name].g/(double)ran[ans.name];
ans.area = (double)siz[ans.name].area / (double)ran[ans.name];
s.insert(ans);
}
printf("%d\n", s.size());
set<Ans>::iterator it;
for (it = s.begin(); it != s.end(); it++) {
printf("%04d %d %.3lf %.3lf\n", (*it).name, ran[(*it).name], (*it).g, (*it).area);
}
}
return 0;
}