1114 Family Property (25分)

PTA链接1114 Family Property (25分)

最怕这种没有难度但是极其耗时的题目。做这类题目事先一定要规划好,画好逻辑图,不能想到哪写到哪,脑子一团浆糊往往能磨蹭的写一个多小时。

题目梗概:

给出一个数n,接下来有n个家庭,每个家庭包括一定的成员,房产数和房产总面积。如果不同的家庭中有相同的成员,则这些家庭可以组成一个家族。求计算有几个家族,输出每个家族中ID最小的,家族成员数,房产数/成员数,房产面积/成员数。

解题流程:

1.创建并查集,创建N个父节点,使一个家庭的全部成员为对应父节点的子集。

2.如果其中一个家庭的父节点为A,但是其中有一个成员已经有归属的父节点B,则将A的父节点设为B从而形成一个家族。

    例如:

7777 6666 -1 0 2 300
6666 5551 5552 1 7777 1 100

     这两个家庭就能形成一个家族。

3.合并家庭的同时将家庭的资产也同时合并。

AC代码

#include<cstdio>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=1010;
int n,father[11010];  
double area[maxn],sets[maxn];

set<int> person;    //储存成员id
vector<int> family;//储存家族 
struct Node{
	int id;
	int meb;
	double set;
	double area;
}node[maxn];

int findFather(int x){
	int a=x;
	while(x!=father[x]){
		x=father[x];
	}
	while(a!=father[a]){
		int z=a;
		a=father[a];
		father[z]=x;
	}
	return x;
}

void Union(int a,int b){
	int fa=findFather(a);
	int fb=findFather(b);
	if(fa!=fb){
		father[fb]=fa;
	}
}

bool cmp(int a,int b){
	if(node[a].area==node[b].area){
		return node[a].id<node[b].id;
	}
	else return node[a].area>node[b].area;
}

int main(){
	//freopen("input.txt","r",stdin);
	scanf("%d",&n);
	int start=10000;  //每个家庭的父节点从start开始计数(0~9999为家庭成员的父节点) 
	for(int i=0;i<11010;i++){
		father[i]=i;          //初始化父节点 
	}
	int id,k;
	for(int i=start;i<start+n;i++){  //i为该家庭的父节点 
		for(int j=0;j<3;j++){
			scanf("%d",&id);
			if(id==-1){      //家庭成员不存在则跳过 
				continue;   
			}
			person.insert(id); 
			if(id!=father[id]){ //该成员已经属于其他家庭 
				int flag=findFather(id);  //将两个家庭合并 
				Union(i,flag);
			}
			father[id]=i;
		}
		scanf("%d",&k);
		for(int j=0;j<k;j++){
			scanf("%d",&id);
			person.insert(id);
			if(id!=father[id]){
				int flag=father[id];
				Union(i,flag);
			}
			father[id]=i;
		}
		scanf("%lf %lf",&sets[i-start],&area[i-start]);
	}
	for(int i=start;i<n+start;i++){  //资产合并 
		k=findFather(i);
		if(k!=i){
			sets[k-start]+=sets[i-start];
			area[k-start]+=area[i-start];
		}
	}
	for(int i=start;i<start+n;i++){   //家族创建   
		if(i==father[i]){  
			k=i-start;
			node[k].area=area[k];
			node[k].set=sets[k];
			node[k].meb=0;
			node[k].id=10000;
			family.push_back(k);
		}
	}
	for(set<int>::iterator it=person.begin();it!=person.end();it++){  //遍历所有人口 
		int id=*it;
		k=findFather(id)-start;
		if(node[k].id>id){
			node[k].id=id;
		}
		node[k].meb++;
	}
	for(int i=0;i<family.size();i++){
		k=family[i];
		node[k].set=node[k].set/node[k].meb*1.0;
		node[k].area=node[k].area/node[k].meb*1.0;
	}
	sort(family.begin(),family.end(),cmp);
	printf("%d\n",family.size());
	for(int i=0;i<family.size();i++){
		k=family[i];
		printf("%04d %d %.3f %.3f\n",node[k].id,node[k].meb,node[k].set,node[k].areid);
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值