PAT (Advanced Level) Practise 1114 Family Property (25) 并查集orDFS

来源:互联网 发布:杨闻萍审计 知乎 编辑:程序博客网 时间:2024/06/05 02:41

1114. Family Property (25)

时间限制
150 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

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:
106666 5551 5552 1 7777 1 1001234 5678 9012 1 0002 2 3008888 -1 -1 0 1 10002468 0001 0004 1 2222 1 5007777 6666 -1 0 2 3003721 -1 -1 1 2333 2 1509012 -1 -1 3 1236 1235 1234 1 1001235 5678 9012 0 1 502222 1236 2468 2 6661 6662 1 3002333 -1 3721 3 6661 6662 6663 1 100
Sample Output:
38888 1 1.000 1000.0000001 15 0.600 100.0005551 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头上,其他的都为0A += (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;}




0 0
原创粉丝点击