L2-007. 家庭房产
时间限制 | 内存限制 | 代码长度限制 | 判题程序 | 作者 |
400ms | 65536kB | 8000B | Standar | 陈越 |
给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。
输入格式:
输入第一行给出一个正整数N(<=1000),随后N行,每行按下列格式给出一个人的房产:
编号 父 母 k 孩子1 ... 孩子k 房产套数 总面积
其中 编号 是每个人独有的一个4位数的编号;父 和 母 分别是该编号对应的这个人的父母的编号(如果已经过世,则显示-1);k(0<=k<=5)是该人的子女的个数;孩子i是其子女的编号。
输出格式:
首先在第一行输出家庭个数(所有有亲属关系的人都属于同一个家庭)。随后按下列格式输出每个家庭的信息:
家庭成员的最小编号 家庭人口数 人均房产套数 人均房产面积
其中人均值要求保留小数点后3位。家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。
输入样例: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输出样例:
3 8888 1 1.000 1000.000 0001 15 0.600 100.000 5551 4 0.750 100.000思路:
用并查集,把每一行输入的数据都合并一下。每次合并都是把两个家族的代表合并(单独的一个人的时候他就是自己家族的代表),并且把编号较小的那个作为代表。合并的同时把编号较大的那个中存的信息添加给编号较小的,并清空编号较大的中保存的信息,这样保证只有在家族的leader中房子套数和面积才不是0。
每个节点的leader就是他所在家族的代表的编号。每次输入的房子套数和面积的时候只需要直接把这些直接添加给家族的代表就行了。
因为如果在输入这个节点的数据时他已经是某个家族的代表,那就应该把要输入的数据+=到原有数据上。如果在输入这个节点的数据的时候他已经是属于某个家族(leader不等于自己)但是不是代表(说明他之前被计算过一次,并且只提供了人头数),就要把数据+=到代表上。
输入的人会有三种情况:
- 不属于任何家族。和父母子女合并完可能是代表也可能不是
- 已经是家族代表。之前已经作为某人的父母或子女被输入
- 属于某个家族不是代表。之前已经作为某人的父母或子女被输入
每次都要把数据“+=”到自己家族代表的上,就是为了防止某个人在被输入的时候已经被加入到某个家族中(情况3),保证数据都集中在家族的代表中。
代码:
1 #include<iostream> 2 #include<stdio.h> 3 #include<set> 4 using namespace std; 5 struct node 6 { 7 int leader;//本家族代表的编号 8 double num;//总人数,如果不是家族的代表就为0 9 double t;//总套数,如果不是家族的代表就为0 10 double m;//总面积,如果不是家族的代表就为0 11 node () 12 { 13 num=1;//初始化时家族只有自己,人数为1 14 t = m = 0;//初始化时没有输入数据,为0 15 } 16 bool operator <(const node b)const//重载小于号,为了利用set排序 17 { 18 if( ( m / num ) == ( b.m / b.num ) ) 19 { 20 return leader < b.leader; 21 } 22 return ( m / num ) > ( b.m / b.num ); 23 } 24 void operator +=( node &b)//方便合并两个家族是数据的处理 25 { 26 num += b.num; 27 m += b.m; 28 t += b.t; 29 b.num = 0; 30 b.m = 0; 31 b.t = 0; 32 } 33 }; 34 node s[10005]; 35 void yasuo(int a, int b)//路径压缩,把路径上的每一个节点的leader都赋为本家族的leader 36 { 37 int i; 38 while(s[a].leader != b) 39 { 40 i = s[a].leader; 41 s[a].leader = b; 42 a = i; 43 } 44 } 45 int hb( int a, int b )//合并家族a,b 46 { 47 int x = a,y = b; 48 while( s[x].leader != x ) x = s[x].leader;//找到本家族的leader, 49 while( s[y].leader != y ) y = s[y].leader;//因为本家族的数据都在家族的leader中,所以合并只需要合并两家族leader 50 if( x != y ) 51 { 52 if( x > y )//交换x,y的值 53 { 54 x ^= y; 55 y ^= x; 56 x ^= y; 57 } 58 s[x] += s[y]; 59 yasuo(a, x); 60 yasuo(b, x); 61 } 62 return x; 63 } 64 int main() 65 { 66 int i = 0; 67 while ( i < 10005 )//初始化数组,leader默认是自己 68 { 69 s[i].leader = i; 70 i++; 71 } 72 cin >> i; 73 int j = 0; 74 while( j < i ) 75 { 76 int a; 77 int k; 78 cin >> a;//输入自己的编号 79 80 cin >> k;//输入父编号 81 if(k != -1)hb(a, k);//与父合并 82 83 cin >> k;//输入母编号 84 if(k != -1)hb(a, k);//与母合并 85 86 cin>>k;//输入孩子个数 87 int jj = 0; 88 while( k-- ) 89 { 90 cin >> jj;//输入孩子 91 hb(a, jj);//与孩子合并 92 } 93 94 cin >> k;//输入房子套数 95 s[ s[a].leader ].t += k;//把数据加给本家族leader 96 97 cin >> k;//输入面积 98 s[ s[a].leader ].m += k;//把数据加给本家族leader 99 j++; 100 } 101 set<node> q;//利用set排序和统计 102 for( i = 0; i <= 10000; i++ ) 103 { 104 if( s[i].m > 0 )//只有家族leader的面积才会不为0 105 { 106 q.insert( s[i] ); 107 } 108 } 109 set<node>::iterator it = q.begin(); 110 cout << q.size() << endl; 111 while( it != q.end() ) 112 { 113 printf("%04d %.0f %.3f %.3f", (*it).leader, (*it).num, (*it).t/(*it).num, (*it).m/(*it).num ); 114 it++; 115 if( it != q.end() )cout << endl; 116 } 117 return 0; 118 }