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; }