1114. Family Property (25)
This time, you are supposed to help us collect the data for family-owned property. Given each person's family members, and the estate(房产)info under his/her own name, we need to know the size of each family, and the average area and number of sets of their real estate.
Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (<=1000). Then N lines follow, each gives the infomation of a person who owns estate in the format:
ID Father Mother k Child1 ... Childk M_estate Area
where ID is a unique 4-digit identification number for each person; Father and Mother are the ID's of this person's parents (if a parent has passed away, -1 will be given instead); k (0<=k<=5) is the number of children of this person; Childi's are the ID's of his/her children;M_estate is the total number of sets of the real estate under his/her name; and Area is the total area of his/her estate.
Output Specification:
For each case, first print in a line the number of families (all the people that are related directly or indirectly are considered in the same family). Then output the family info in the format:
ID M AVG_sets AVG_area
where ID is the smallest ID in the family; M is the total number of family members; AVG_sets is the average number of sets of their real estate; and AVG_area is the average area. The average numbers must be accurate up to 3 decimal places. The families must be given in descending order of their average areas, and in ascending order of the ID's if there is a tie.
Sample Input:10 6666 5551 5552 1 7777 1 100 1234 5678 9012 1 0002 2 300 8888 -1 -1 0 1 1000 2468 0001 0004 1 2222 1 500 7777 6666 -1 0 2 300 3721 -1 -1 1 2333 2 150 9012 -1 -1 3 1236 1235 1234 1 100 1235 5678 9012 0 1 50 2222 1236 2468 2 6661 6662 1 300 2333 -1 3721 3 6661 6662 6663 1 100Sample Output:
3 8888 1 1.000 1000.000 0001 15 0.600 100.000 5551 4 0.750 100.000
并查集,将所有有亲戚关系的节点全部合并到一个并查集里,子节点将地产的信息和人数信息也要合并到父节点里面去,但是感觉太长了。。。看网上有直接用DFS的
就七八十行,输了。。。
#include <cstdio>
#include <cstring>
#include <map>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
struct node {
int id, cou; //cou为集合中的元素数目
double suma, sums;
node() { cou = 0; suma = 0; sums = 0; }
node(int id) : id(id) { cou = 0; suma = 0; sums = 0; }
}fam[10], f[11111], ans[11111];
const int INF = 0x7fffffff;
int N;
bool cmp(node a, node b) {
if (fabs(a.suma - b.suma) < 1e-8) {
return a.id < b.id;
}
else {
return a.suma > b.suma;
}
}
int getf(int x) {
return f[x].id == x ? x : f[x].id = getf(f[x].id);
}
void Merge(int x, int y) {
int xx = getf(x), yy = getf(y);
int fx = min(xx, yy), fy = max(xx, yy);
if (fx != fy) {
f[fy].id = f[fx].id; //父节点吸收吸收子节点
f[fx].sums += f[fy].sums;
f[fx].suma += f[fy].suma;
f[fx].cou += f[fy].cou;
}
}
int main()
{
scanf("%d", &N);
map<int, int> m; //用来记录ID的出现情况,m[i]不为零说明出现过
bool vis[10001]; //用来记录一个ID的重复情况,为true时说明以前出现过
//并查集初始化
for (int i = 0; i <= 9999; i++) {
f[i].id = i;
}
memset(vis, false, sizeof(vis));
for (int t = 1; t <= N; t++) {
int id, fa, ma, k, len, Set, Area, minn, index, ff;
scanf("%d%d%d", &id, &fa, &ma);
k = 0; //fam数组的长度
minn = INF; //minn用来存根节点的最小值
index = 0; //index为输入的一组ID里面根节点最小的所在下标
m[id]++; //说明这个ID出现过
ff = getf(id);
if (ff < minn) {
minn = ff;
index = 0;
}
fam[k++] = node(id);
if (fa != -1) {
m[fa]++;
fam[k] = node(fa);
ff = getf(fa);
if (ff < minn) {
minn = ff;
index = k;
}
k++;
}
if (ma != -1) {
m[ma]++;
fam[k] = node(ma);
ff = getf(ma);
if (ff < minn) {
minn = ff;
index = k;
}
k++;
}
scanf("%d", &len);
while (len--) {
scanf("%d", &fam[k].id);
m[fam[k].id]++;
ff = getf(fam[k].id);
if (ff < minn) {
minn = ff;
index = k;
}
k++;
}
scanf("%d%d", &Set, &Area);
int c = 0;
for (int i = 0; i < k; i++) {
Merge(fam[index].id, fam[i].id);
//在集合里去重,也就是以前加入集合的不用再加入了
if (!vis[fam[i].id]) {
vis[fam[i].id] = true;
c++;
}
}
int root = getf(fam[index].id);
f[root].sums += Set;
f[root].suma += Area;
f[root].cou += c;
}
for (int i = 0; i <= 9999; i++) {
f[i].id = getf(f[i].id);
}
int LEN = 0;
for (int i = 0; i <= 9999; i++) {
//说明m[i]在输入的数里面
if (m[i] != 0) {
if (f[i].id == i) {
ans[LEN] = f[i];
ans[LEN].suma /= ans[LEN].cou;
ans[LEN].sums /= ans[LEN].cou;
LEN++;
}
}
}
sort(ans, ans + LEN, cmp);
printf("%d\n", LEN);
for (int i = 0; i < LEN; i++) {
printf("%04d %d %.3f %.3f\n", ans[i].id, ans[i].cou, ans[i].sums, ans[i].suma);
}
return 0;
}
用DFS直接找连通域并累加人数和地产信息
#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 10000 + 10;
int N, C, Set[maxn], Area[maxn], ID;
double S, A;
bool f[maxn];
struct node {
int id, cou;
double a_s, a_a;
node(int id = 0, int cou = 0, double a_s = 0, double a_a = 0) : id(id), cou(cou), a_s(a_s), a_a(a_a) {};
}p[maxn];
bool cmp(node a, node b) {
if (fabs(a.a_a - b.a_a) < 1e-8) {
return a.id < b.id;
}
else {
return a.a_a > b.a_a;
}
}
vector<int> m[maxn];
void dfs(int x) {
ID = min(ID, x);
C++; //累加人数
f[x] = false; //标记不再重走
S += (1.0 * Set[x]); //累加地产信息,地产挂在第一个id头上,其他的都为0
A += (1.0 * Area[x]);
for (int i = 0; i < m[x].size(); i++) {
if (f[m[x][i]]) {
dfs(m[x][i]);
}
}
}
int main()
{
scanf("%d", &N);
memset(f, false, sizeof(f));
for (int t = 0; t < N; t++) {
int id, fa, ma, len, tem;
scanf("%d%d%d", &id, &fa, &ma);
f[id] = true; //记录一个数出现过
if (fa != -1) {
f[fa] = true;
m[id].push_back(fa);
m[fa].push_back(id);
}
if (ma != -1) {
f[ma] = true;
m[id].push_back(ma);
m[ma].push_back(id);
}
scanf("%d", &len);
while (len--) {
scanf("%d", &tem);
f[tem] = true;
m[id].push_back(tem);
m[tem].push_back(id);
}
scanf("%d%d", &Set[id], &Area[id]);
}
int LEN = 0;
//0 - 9999扫描
for (int i = 0; i < 10000; i++) {
//输入过的
if (f[i]) {
ID = 10000;
C = 0;
S = A = 0;
dfs(i);
p[LEN++] = node(ID, C, S / (1.0 * C), A / (1.0 * C));
}
}
sort(p, p + LEN, cmp);
printf("%d\n", LEN);
for (int i = 0; i < LEN; i++) {
printf("%04d %d %.3f %.3f\n", p[i].id, p[i].cou, p[i].a_s, p[i].a_a);
}
return 0;
}