7-11 家庭房产

给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。

输入格式:

输入第一行给出一个正整数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

分析

看到要求输出每个家庭的信息,很容易想到用并查集来把输入的这些人分类归为哪个家庭。那么问题来了,如何知道每个家庭成员的最小编号,以及人数,人均房数,人均面积?这个时候就需要使用辅助数组了。

void join(int a,int b){
	ex[a]=true;
	ex[b]=true;
	a=find(a);
	b=find(b);
	if(a!=b){
		int mx=max(a,b),mn=min(a,b);
		re[mx]=mn;//以编号小的为根 
		pe[mn]+=pe[mx];//添加到编号小的上 
		ho[mn]+=ho[mx];
		area[mn]+=area[mx];
	}
}
struct family{//一个家庭 
	int id,pp,hnum,anum;//最小成员id,家庭人数,总房数,总面积 
	bool operator<(const family &a)const{
		double avga1,avga2;
		avga1=anum*1.0/pp;
		avga2=a.anum*1.0/a.pp;
		if(avga1!=avga2)return avga1>avga2;
		return id<a.id;
	}
};
for(int i=0;i<N;i++){
		if(ex[i]&&re[i]==i){//如果此人真实存在且为根 
			families.push_back({i,pe[i],ho[i],area[i]});
		}
	}

像这样,用ex数组来标记存在的人,以编号小的那个人为根,将人数,房数,面积,全都累加到那一个人身上。用结构体数组来存储家庭信息,然后遍历并查集,将信息录入结构体然后排序输出结果

答案

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int n,cnt=0,k;
struct edge{//关系边 
	int a;
	int b;
}ed[N];
struct family{//一个家庭 
	int id,pp,hnum,anum;//最小成员id,家庭人数,总房数,总面积 
	bool operator<(const family &a)const{
		double avga1,avga2;
		avga1=anum*1.0/pp;
		avga2=a.anum*1.0/a.pp;
		if(avga1!=avga2)return avga1>avga2;
		return id<a.id;
	}
};
int re[N],pe[N],ho[N],area[N];//并查集容器、记录人数,记录房数,记录面积 
bool ex[N]={false};//判断并查集中哪些人真实存在 
void init(){//初始化 
	for(int i=0;i<N;i++){
		re[i]=i;
		pe[i]=1;
	}
}
int find(int a){
	if(re[a]==a)return a;
	return re[a]=find(re[a]);
}
void join(int a,int b){
	ex[a]=true;
	ex[b]=true;
	a=find(a);
	b=find(b);
	if(a!=b){
		int mx=max(a,b),mn=min(a,b);
		re[mx]=mn;//以编号小的为根 
		pe[mn]+=pe[mx];//添加到编号小的上 
		ho[mn]+=ho[mx];
		area[mn]+=area[mx];
	}
}
int main() {
	cin>>n;
	init();
	int id,fa,mo,child;
	for(int i=0;i<n;i++){
		cin>>id>>fa>>mo>>k;
		//添加关系边 
		if(fa!=-1)
		ed[cnt++]={id,fa};
		if(mo!=-1)
		ed[cnt++]={id,mo};
		ex[id]=true;//标记该人存在 
		for(int j=0;j<k;j++){
			cin>>child;
			ed[cnt++]={id,child};
		} 
		cin>>ho[id]>>area[id];
	}
	for(int i=0;i<cnt;i++){
		join(ed[i].a,ed[i].b);
	}
	vector<family> families;
	for(int i=0;i<N;i++){
		if(ex[i]&&re[i]==i){//如果此人真实存在且为根 
			families.push_back({i,pe[i],ho[i],area[i]});
		}
	}
	sort(families.begin(),families.end());//排序 
	cout<<families.size()<<endl;
	for(int i=0;i<families.size();i++){
		cout<<setw(4)<<setfill('0')<<families[i].id<<" "<<families[i].pp<<" "<<fixed<<setprecision(3)<<families[i].hnum*1.0/families[i].pp<<" "<<families[i].anum*1.0/families[i].pp<<endl;
	}
	return 0;
}

小结

涉及到集合问题可以想到用并查集
如若输入不是标准关系式,则将其转换为关系式,然后加入到并查集中
对于此题中要求的,输出家庭中最小成员,人数,人均房数,人均面积可以以并查集的根为最小成员id,用数组记录下每个人的房数和面积,在加入的时候全都累加到数组以根为下标的值上

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值