PTA L2-007 家庭房产 (25 分) 并查集 题目解析

 题目分析:

题目给出数据为:人编号(4位),人房子信息,人与人的关系(有关系就是一个家庭的)。

所求:家庭数目、家庭信息(先求出成员数、房子总数、房子总面积即可)

抽象分析:给定一堆点,点与点的连通关系,求有几个连通区域,此连通区域信息

所用算法:并查集

#include<iostream>
#include<vector>
#include<set>
#include<algorithm>
#include<cstdio>
#define iIN(x,y) for(int i=x;i<y;i++)
#define jIN(x,y) for(int j=x;j<y;j++)
using namespace std;
vector<int> house;//房子数量
vector<int> S;    //房子面积
vector<int> people;//个人信息
int root[10000]; //root[x]里面存的是x的根 
int mark[10000];
//a1 a2 a3 a4存家庭信息 
vector<int> a1;
vector<int> a2;
vector<double> a3;
vector<double> a4;
int getRoot(int x){ //得到people[x]的根节点 
	while(root[x]!=x){
		x=root[x];
	}
	return x;
}
int f(int x,int y){
	if(a4[x]/a2[x]>a4[y]/a2[y])return 1;
	else if(a4[x]/a2[x]==a4[y]/a2[y] && a1[x]<a1[y])return 1;
	else return 0;
}
int main(){
	int N;
	int father,mother;//父亲、母亲的编号 
	int child_amount;//孩子数量 
	int house_amount,house_S;//房子套数、房子总面积 
	int box;//装int数据的变量 
	int mine;
	int root1,root2;
	vector<int> family;
	iIN(0,10000){
		root[i]=i;//每个点根节点初始化为自己 
	}
	cin>>N;
	iIN(0,N){
		family.clear();
		cin>>mine>>father>>mother;
		if(father!=-1)family.push_back(father);
		if(mother!=-1)family.push_back(mother);
		cin>>child_amount;
		while(child_amount--){
			cin>>box;
			family.push_back(box);
		} //得到了family 
		cin>>house_amount>>house_S;//得到了房子数量 房子总面积
		for(int k=0;k<family.size();k++){ //mine取值最小的那个 
			if(mine>family[k]){
				int box=mine;
				mine=family[k];
				family[k]=box;
			}
		}
		people.push_back(mine);
		house.push_back(house_amount);
		S.push_back(house_S);
		root1=getRoot(mine);
		for(int j=0;j<family.size();j++){
			root2=getRoot(family[j]);
			root[root2]=root1;
		} //并查集合并 
	}
	iIN(0,people.size()){ //生成家庭i 信息保存至a1[i] a2[i] a3[i] a4[i]
		if(mark[people[i]]==-1)continue;//people[i]是i人的num 
		a1.push_back(people[i]);//编号
		//a2.push_back(1);//人口数 
		a3.push_back(house[i]);//房子数量 
		a4.push_back(S[i]);   //房子面积 
		int r=getRoot(people[i]); //先找根 同根即同家庭 
		int a2_count=0;
		for(int k=0;k<10000;k++){ //计算下这个家庭有多少人 
			if(getRoot(k)==r)a2_count++;
		}
		a2.push_back(a2_count);
		jIN(i+1,people.size()){
			int now=a1.size()-1;//最后一项,也就是刚加入的项
			if(getRoot(people[j])==r){ //同一个家庭 
				if(a1[now]>people[j])a1[now]=people[j];
				a3[now]+=house[j];
				a4[now]+=S[j];
				mark[people[j]]=-1;
			}
		}
	}
	vector<int> order;
	iIN(0,a1.size()){
		order.push_back(i);
	}
	sort(order.begin(),order.end(),f);
	cout<<order.size()<<endl;
	jIN(0,order.size()){
		int i=order[j];
		printf("%04d %d %.3f %.3f\n",a1[i],a2[i],a3[i]/a2[i],a4[i]/a2[i]);
	}
	return 0;
}

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会写代码的孙悟空

赠人玫瑰 手有余香

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值