A1114. Family Property
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 100
Sample Output:
3 8888 1 1.000 1000.000 0001 15 0.600 100.000 5551 4 0.750 100.000
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<string> 5 #include<vector> 6 using namespace std; 7 double estate[10000], area[10000]; 8 int father[10000], familyNum[10000], tb[10000]; 9 bool cmp(int a, int b){ 10 if(area[a] != area[b]) 11 return area[a] > area[b]; 12 else return a < b; 13 } 14 int findFather(int x){ 15 int temp = x; 16 while(x != father[x]){ 17 x = father[x]; 18 } 19 int temp2; 20 while(temp != x){ 21 temp2 = father[temp]; 22 father[temp] = x; 23 temp = temp2; 24 } 25 return x; 26 } 27 void merge(int a, int b){ 28 if(a == -1 || b == -1) 29 return; 30 int af = findFather(a); 31 int bf = findFather(b); 32 if(af == bf) 33 return; 34 if(af > bf) 35 swap(af, bf); 36 father[bf] = af; 37 } 38 int main(){ 39 int N; 40 scanf("%d", &N); 41 int id, idf, idm, child; 42 int chiN; 43 for(int i = 0; i < 10000; i++){ 44 estate[i] = 0; 45 area[i] = 0; 46 father[i] = i; 47 familyNum[i] = 0; 48 tb[i] = 0; 49 } 50 for(int i = 0; i < N; i++){ 51 cin >> id >> idf >> idm >> chiN; 52 tb[id] = tb[idf] = tb[idm] = 1; 53 merge(id, idf); 54 merge(id, idm); 55 int son; 56 for(int j = 0; j < chiN; j++){ 57 cin >> son; 58 tb[son] = 1; 59 merge(id, son); 60 } 61 cin >> estate[id] >> area[id]; 62 } 63 int cnt = 0; 64 vector<int> ans; 65 for(int i = 0; i < 10000; i++){ 66 if(tb[i] == 1){ 67 int ff = findFather(i); 68 if(ff != i){ 69 estate[ff] += estate[i]; 70 area[ff] += area[i]; 71 } 72 familyNum[ff]++; 73 if(i == ff){ 74 cnt++; 75 ans.push_back(i); 76 } 77 78 } 79 } 80 for(int i = 0; i < 10000; i++){ 81 if(tb[i] == 1 && father[i] == i){ 82 int Num = familyNum[i]; 83 area[i] = area[i] / (double)Num; 84 estate[i] = estate[i] / (double)Num; 85 } 86 } 87 sort(ans.begin(), ans.end(), cmp); 88 printf("%d\n", cnt); 89 for(int i = 0; i < ans.size(); i++){ 90 printf("%04d %d %.3f %.3f\n", ans[i], familyNum[ans[i]], estate[ans[i]], area[ans[i]]); 91 } 92 cin >> N; 93 return 0; 94 }
总结:
1、由于一个人既有双亲又有N多个孩子,所以用树形结构肯定不行。只能用并查集或者图搜索。
2、并查集:并查集仅仅对父母、子女的关系进行合并处理。房子数、面技数、家庭人口等先不计算,仅仅存在每个人各自的对应数组中。由于序号不是连续的1到N,因此father数组中会有很多无效节点,需要一个tb数组在输入的时候就记录哪些是有效的节点。 在并查集处理完家庭关系之后,对father数组再次遍历,当遇到非根节点时,查找到他对应的根节点,并把房子、面积、等累加至根节点对应的数组中。
3、由于要求输出的id为家族中最小id,所以在两个root合并时,要将更小的root作为新的root。