PAT甲级——1114 Family Property (并查集)
此文章同步发布在我的CSDN上https://blog.csdn.net/weixin_44385565/article/details/89930332
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 (≤). Then N lines follow, each gives the infomation of a person who owns estate in the format:
ID
Father
Mother
k Child1⋯Childk Mestate 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) is the number of children of this person; Childi's are the ID
's of his/her children; Mestate 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
AVGsets AVGarea
where ID
is the smallest ID in the family; M
is the total number of family members; AVGsets is the average number of sets of their real estate; and AVGarea 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 100
Sample Output:
3
8888 1 1.000 1000.000
0001 15 0.600 100.000
5551 4 0.750 100.000
题目大意:根据给出的数据分类出各个家庭,然后输出家庭个数;接下来输出每个家庭的成员ID(只需输出家庭成员中最小的ID)、成员数量、平均房产数量、平均房产面积,输出顺序为平均房产面积降序、ID升序。
思路:用并查集S给家庭分类,为了方便找出最小的家庭成员ID,对并查集的操作稍作修改,集合元素初始化为对应的下标,若S[X]==X,则X为根,unionSet()函数将大根集合并到小根集合里;家庭成员计数时需要对已经访问过的ID进行标记,防止重复计数,用visit数组标记每个ID。
总结:其实我是比较害怕这类问题的,看起来简单,可是信息一多思考起来就容易混乱,需要很细心很耐心地分析,用不到什么算法知识却超级消耗时间~
1 #include <iostream> 2 #include <vector> 3 #include <unordered_map> 4 #include <algorithm> 5 using namespace std; 6 struct node1 { 7 int ID, fID, mID, k, Me, area; 8 vector <int> child; 9 }; 10 struct node2 { 11 int sumM = 0, sumSets = 0, sumArea = 0; 12 }; 13 struct node3 { 14 int ID, M; 15 float AVGs, AVGa; 16 }; 17 vector <int> S(10000); 18 vector <bool> visit(10000, false); 19 void initialize();//对集合S进行初始化 20 bool cmp(node3 &a, node3 &b);//排序规则 21 int getNum(node1 &a);//获取家庭成员的数量 22 int find(int X); 23 void unionSet(int X, int Y); 24 int main() 25 { 26 int N; 27 scanf("%d", &N); 28 vector <node1> data(N); 29 unordered_map <int, node2> mp; 30 initialize(); 31 for (int i = 0; i < N; i++) { 32 node1 tmp; 33 scanf("%d%d%d%d", &tmp.ID, &tmp.fID, &tmp.mID, &tmp.k); 34 if (tmp.fID != -1) 35 unionSet(tmp.ID, tmp.fID); 36 if (tmp.mID != -1) 37 unionSet(tmp.ID, tmp.mID); 38 if (tmp.k != 0) { 39 for (int j = 0; j < tmp.k; j++) { 40 int cID; 41 scanf("%d", &cID); 42 tmp.child.push_back(cID); 43 unionSet(tmp.ID, cID); 44 } 45 } 46 scanf("%d%d", &tmp.Me, &tmp.area); 47 data[i] = tmp; 48 } 49 for (int i = 0; i < N; i++) { 50 int ID = find(data[i].ID); 51 mp[ID].sumM += getNum(data[i]); 52 mp[ID].sumSets += data[i].Me; 53 mp[ID].sumArea += data[i].area; 54 } 55 vector <node3> ans; 56 for (auto it = mp.begin(); it != mp.end(); it++) { 57 int ID = it->first, 58 M = it->second.sumM; 59 float AVGs = it->second.sumSets*1.0 / M, 60 AVGa = it->second.sumArea*1.0 / M; 61 ans.push_back({ ID,M,AVGs,AVGa }); 62 } 63 sort(ans.begin(), ans.end(), cmp); 64 printf("%d\n", ans.size()); 65 for (int i = 0; i < ans.size(); i++) 66 printf("%04d %d %.3f %.3f\n", ans[i].ID, ans[i].M, ans[i].AVGs, ans[i].AVGa); 67 return 0; 68 } 69 int getNum(node1 &a) { 70 int n = 0; 71 if (!visit[a.ID]) { 72 n++; 73 visit[a.ID] = true; 74 } 75 if ((a.fID != -1 )&& (!visit[a.fID])) { 76 n++; 77 visit[a.fID] = true; 78 } 79 if ((a.mID != -1) && (!visit[a.mID])) { 80 n++; 81 visit[a.mID] = true; 82 } 83 if (a.k != 0) { 84 for (int i = 0; i < a.k; i++) { 85 if (!visit[a.child[i]]) { 86 n++; 87 visit[a.child[i]] = true; 88 } 89 } 90 } 91 return n; 92 } 93 void unionSet(int X, int Y) { 94 int rootX = find(X), 95 rootY = find(Y); 96 if (rootX > rootY) 97 S[rootX] = S[rootY]; 98 else 99 S[rootY] = S[rootX]; 100 } 101 int find(int X) { 102 if (S[X] == X) { 103 return X; 104 } 105 else { 106 return S[X] = find(S[X]);//递归地压缩路径 107 } 108 } 109 void initialize() { 110 for (int i = 0; i < 10000; i++) 111 S[i] = i;//将集合元素初始化为对应的下标,每个集合的根节点就是当前家庭的最小ID 112 } 113 bool cmp(node3 &a, node3 &b) { 114 if (a.AVGa != b.AVGa) 115 return a.AVGa > b.AVGa; 116 else 117 return a.ID < b.ID; 118 }