PAT 1114 Family Property(并查集)

PAT1114 Family Property

原题

在这里插入图片描述

题目大意

题目中给定了一些人的家庭情况及房产情况,要求输出:

  1. 家庭的个数(祖先后代全算一个家庭)
  2. 按照一定次序输出 ID 该家庭里人数 平均房子栋数 平均房子面积

此处ID为该家庭里的最小ID

思路

该题考察的是并查集。

  • 如果要按照一定规则输出的话应该需要构建一个结构体来进行排序
  • 因为是输出家庭里的最小ID,所以在合并的时候可以让那个父亲ID大的指向小的
  • 关于家庭人数及平均房产等,在结构体里我们可以设定属性为家庭人数,总房产栋数,总面积,最后再求平均。而结构体值的变化应该在初始化及合并的时候进行,可以用一个set集合存储现在有的家庭,在合并的时候删除其一,同时也可以实现排序。

代码

尝试:

#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
int fa[10010]={0};
bool isRoot[10010]={false};
set<int> snumber;
struct family{
	int smallid,sumpeople;
	double sumset,sumarea;
	friend bool operator < (const family& a, const family& b)
    {
        return a.sumarea/a.sumpeople==b.sumarea/b.sumpeople?a.smallid<b.smallid:a.sumarea/a.sumpeople>b.sumarea;
    }
};
int findfather(int v){
	if(v==fa[v]) return v;
	else{
		int f=findfather(fa[v]);
		fa[v]=f;
		return f;
	}
}
void Union(int a,int b){
	int faA=findfather(a);
	int faB=findfather(b);
	if(faA<faB){
		for(auto it=snumber.begin();it!=snumber.end();it++) if(fa[*it]==fa[b]) fa[*it]=faA;
		fa[b]=faA;
	} 
	else{
		for(auto it=snumber.begin();it!=snumber.end();it++) if(fa[*it]==fa[a]) fa[*it]=faB;
		fa[a]=faB;
	}
}
bool cmp(family a,family b){
	return a.sumarea/a.sumpeople==b.sumarea/b.sumpeople?a.smallid<b.smallid:a.sumarea/a.sumpeople>b.sumarea/b.sumpeople;
}
int main(){
	int n;
	cin>>n;
	int id,father,mom,sonnum;
	double mset,area;
	vector<family> v;
	map<int,family> m;
	for(int i=0;i<n;i++){
		set<family> s;
		cin>>id>>father>>mom>>sonnum;
		int addnumber=0;
	//	cout<<fa[id]<<endl;
		if(fa[id]==0){
			fa[id]=id;
		} 
		else{
			s.insert(m[fa[id]]);
			//cout<<1<<endl;
		} 
		if(snumber.find(id)==snumber.end()) addnumber++;
		snumber.insert(id);
		if(father!=-1){
		//	cout<<"!"<<endl;
			if(snumber.find(father)==snumber.end()) addnumber++;
			if(fa[father]==0){
				fa[father]=father;
			} 
			else{
				cout<<s.size()<<endl;
				s.insert(m[fa[father]]);
			//	cout<<2<<" "<<m[fa[father]].smallid<<" "<<s.size()<<endl;
			} 
			snumber.insert(father);
		} 
		if(mom!=-1){
			if(snumber.find(mom)==snumber.end()) addnumber++;
		    if(fa[mom]==0){
		    	fa[mom]=mom;
			} 
			else{
				s.insert(m[fa[mom]]);
			//	cout<<3<<" "<<m[fa[mom]].smallid<<" "<<s.size()<<endl;
			} 
	     	snumber.insert(mom);
		}
		int sid=fa[id];
		//cout<<sid<<endl;
		//cout<<"father- id:"<<fa[id]<<" father:"<<fa[father]<<" mom:"<<fa[mom]<<" "; 
		vector<int> sonv(sonnum);
		for(int i=0;i<sonnum;i++){
			cin>>sonv[i];
			if(sonv[i]<sid)  sid=sonv[i];
			if(snumber.find(sonv[i])==snumber.end()) addnumber++;
			if(fa[sonv[i]]==0){
				fa[sonv[i]]=sonv[i];
			} 
			else{
				s.insert(m[fa[sonv[i]]]);
				//cout<<4<<endl;
			} 
			snumber.insert(sonv[i]);
			//cout<<sonv[i]<<":"<<fa[sonv[i]]<<" ";
		} 
		cout<<endl;
		cin>>mset>>area;
		double addset=mset,addarea=area;
		for(auto it=s.begin();it!=s.end();it++){
			cout<<it->smallid<<endl;
			addset+=it->sumset;
			addarea+=it->sumarea;
			addnumber+=it->sumpeople;
			//cout<<5<<endl;
		}
		//cout<<addset<<" "<<addarea<<" "<<addnumber<<endl;
		if(father!=-1&&findfather(father)) sid=min(sid,fa[father]);
		if(mom!=-1&&findfather(mom))	sid=min(sid,fa[mom]);
		Union(sid,id);
		if(father!=-1) Union(father,sid);
		if(mom!=-1) Union(mom,sid);
		for(int i=0;i<sonnum;i++) Union(sonv[i],sid);
		//family f={sid,addnumber+m[sid].sumpeople,mset+m[sid].sumset,area+m[sid].sumarea};
		family f={sid,addnumber,addset,addarea};
		m[sid]=f;
		//cout<<sid<<": "<<m[sid].sumpeople<<" "<<m[sid].sumset<<" "<<m[sid].sumarea<<endl;
	}
	for(auto it=snumber.begin();it!=snumber.end();it++){
		isRoot[findfather(*it)]=true;
		//cout<<*it<<"  "<<findfather(*it)<<endl;
	}
	int ans=0;
	for(auto it=snumber.begin();it!=snumber.end();it++){
		if(isRoot[*it]){
			v.push_back(m[*it]);
		}	
	//	cout<<*it<<" "<<isRoot[*it]<<"  "<<m[*it].smallid<<"  "<<m[*it].sumpeople<<"  "<<m[*it].sumset<<"  "<<m[*it].sumarea<<endl;
	}
	printf("%d\n",v.size());
	sort(v.begin(),v.end(),cmp);
	for(int i=0;i<v.size();i++){
		printf("%04d %d %.3f %.3f\n",v[i].smallid,v[i].sumpeople,v[i].sumset/v[i].sumpeople,v[i].sumarea/v[i].sumpeople);
	}
	return 0;
}

以上代码没有解决这个问题。
(稍后继续修改更新)

小收获

尝试的代码其实并没有解决这个问题。暂时没调试出来的问题是:在这里插入图片描述
(此处读者看可能有些疑惑。可以对照着我//后的注释来看,这里我稍微解释一下)
(-0-|||之所以这样输出是因为之前点devc++的调试一直有问题所以不常用devc++的调试功能,但刚刚参考完其他博文的步骤 好像又可以了?)
第四行的1代表现在s集合里有一个元素,但经过第五行(判断并加入m[fa[father]])大小还是1,第六行也还是1。 试了很久也暂时没发现是哪里出了问题,因为m[fa[id]]和m[fa[father]]不同,不应该会被消除重复值,大小应该为2.
虽然用这种方法花了一个下午还没有解出来,但是有很多收获:

  • set类型用结构体需要重载<
  • 更加熟悉并查集的使用
  • 此类代码的运用:
for(auto it=snumber.begin();it!=snumber.end();it++){
		isRoot[findfather(*it)]=true;
	}
  • 浮点数位数控制
    printf(%m.nf) 表示打印至少m个字符宽度(包括整数、小数点和小数部分的位数),n位小数
for(int i=0;i<v.size();i++){
		printf("%04d %d %.3f %.3f\n",v[i].smallid,v[i].sumpeople,v[i].sumset/v[i].sumpeople,v[i].sumarea/v[i].sumpeople);
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值