PAT(Advanced)甲级---1114 Family Property (25 分)【DFS,并查集】

This time, you are supposed to help us collect the data for family-owned property. Given each person's family members, and the estate(房产)info under his/her own name, we need to know the size of each family, and the average area and number of sets of their real estate.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (≤1000). Then N lines follow, each gives the infomation of a person who owns estate in the format:

ID Father Mother k Child​1​​⋯Child​k​​ M​estate​​ Area

where ID is a unique 4-digit identification number for each person; Father and Mother are the ID's of this person's parents (if a parent has passed away, -1 will be given instead); k (0≤k≤5) is the number of children of this person; Child​i​​'s are the ID's of his/her children; M​estate​​ is the total number of sets of the real estate under his/her name; and Area is the total area of his/her estate.

Output Specification:

For each case, first print in a line the number of families (all the people that are related directly or indirectly are considered in the same family). Then output the family info in the format:

ID M AVG​sets​​ AVG​area​​

where ID is the smallest ID in the family; M is the total number of family members; AVG​sets​​ is the average number of sets of their real estate; and AVG​area​​is the average area. The average numbers must be accurate up to 3 decimal places. The families must be given in descending order of their average areas, and in ascending order of the ID's if there is a tie.

Sample Input:

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

Sample Output:

3
8888 1 1.000 1000.000
0001 15 0.600 100.000
5551 4 0.750 100.000

题目大意:给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。首先在第一行输出家庭个数(所有有亲属关系的人都属于同一个家庭)。随后按下列格式输出每个家庭的信息:家庭成员的最小编号 家庭人口数 人均房产套数 人均房产面积。其中人均值要求保留小数点后3位。家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。

 代码一:DFS

首先对每个成员(父母、孩子进行编码),然后DFS,连通块个数就是家庭的个数,Head为DFS参数,若当前元素id更小则更新Head,同时计算总人数,房产总面积以及房产套数。

#include<cstdio>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 10000;

struct node{
	int sets=0,totalA=0;
	vector<int> member;
}peo[maxn];

struct node2{
	int id, M;
	double AvgS, AvgA;
};
vector<node2> ans;
map<int, int> m;
map<int, int> i_id;
bool visit[maxn];
int index = 1;

bool cmp(node2 a, node2 b){
	return a.AvgA != b.AvgA ? a.AvgA > b.AvgA:a.id < b.id;
}

void code(int id){  //编码
	m[id] = index;
	i_id[index] = id;
	index++;
}

void dfs(int now,int &Head,int &M,int &totalS,int &totalA){
	visit[now] = true;
	M++;
	if (i_id[now] < i_id[Head]) Head = now;
	totalA += peo[now].totalA;
	totalS += peo[now].sets;
	for (auto x : peo[now].member) {
		if(!visit[x])dfs(x, Head, M, totalS, totalA);
	}
}

int main(){
	int N;
	int id, fa, mo, k, c;
	scanf("%d", &N);
	//编码,存储
	for (int i = 0; i < N; i++){
		scanf("%d%d%d%d", &id, &fa, &mo,&k);
		if (!m[id]) code(id);
		if (!m[fa] && fa != -1)code(fa);
		if (fa != -1){
			peo[m[id]].member.push_back(m[fa]);
			peo[m[fa]].member.push_back(m[id]);
		}
		if (!m[mo] && mo != -1)code(mo);
		if (mo != -1){
			peo[m[id]].member.push_back(m[mo]);
			peo[m[mo]].member.push_back(m[id]);  
		}
		for (int j = 0; j < k; j++){
			scanf("%d", &c);
			if (!m[c])code(c);
			peo[m[id]].member.push_back(m[c]);
			peo[m[c]].member.push_back(m[id]);
		}
		scanf("%d%d", &peo[m[id]].sets, &peo[m[id]].totalA);
	}
	for (int i = 1; i < index;i++){
		int Head = i, M = 0, totalS = 0, totalA = 0;
		if (!visit[i]){
			dfs(i, Head, M, totalS, totalA);
			int head = i_id[Head];
			node2 t;
			t.id = head; t.M = M; t.AvgS = totalS*(1.0) / M; t.AvgA = totalA*(1.0) / M;
			ans.push_back(t);
		}
	}
	sort(ans.begin(), ans.end(),cmp);
	printf("%d\n", ans.size());
	for (auto it = ans.begin(); it != ans.end(); it++){
		printf("%04d %d %.3lf %.3lf\n", it->id, it->M, it->AvgS, it->AvgA);
	}
}

代码二:并查集

参考柳神博客

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 10000;

struct node{
	int id, M, A;
}data[1005];		//保存数据

struct node2{
	int id, members=0;
	double avgS=0.0, avgA=0.0;
	bool isFather = false;   //标记是否根节点
}ans[maxn];		//以id为索引存储答案的散列

bool cmp(node2 a, node2 b){
	return a.avgA != b.avgA ? a.avgA > b.avgA:a.id < b.id;
}

bool visit[maxn];
int father[maxn];

int findFather(int x){
	return x == father[x] ? x : father[x] = findFather(father[x]);
}

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

int main(){
	int N;
	scanf("%d", &N);
	for (int i = 0; i < maxn; i++)father[i] = i;
	int fid, mid, cid,k;
	//建立集合
	for (int i = 0; i <N; i++){
		scanf("%d%d%d%d", &data[i].id, &fid, &mid, &k);
		visit[data[i].id] = true;
		if (fid != -1){
			visit[fid] = true;
			Union(data[i].id, fid);
		}
		if (mid != -1){
			visit[mid] = true;
			Union(data[i].id, mid);
		}
		for (int j = 0; j < k; j++){
			scanf("%d", &cid);
			visit[cid] = true;
			Union(data[i].id, cid);
		}
		scanf("%d%d", &data[i].M, &data[i].A);
	}
	
	//置根节点
	for (int i = 0; i < N; i++){
		int id = findFather(data[i].id);
		ans[id].id = id;
		ans[id].avgS += data[i].M;
		ans[id].avgA += data[i].A;
		ans[id].isFather = true;
	}
	//统计各家庭人数、总家庭数
	int cnt = 0;
	for (int i = 0; i < maxn; i++){
		if (visit[i])ans[findFather(i)].members++;
		if (ans[i].isFather)cnt++;
	}
	//计算均值
	for (int i = 0; i < maxn; i++) {
		if (ans[i].isFather) {
			ans[i].avgS = (double)(ans[i].avgS * 1.0 / ans[i].members);
			ans[i].avgA = (double)(ans[i].avgA * 1.0 / ans[i].members);
		}
	}
	sort(ans, ans + maxn, cmp);
	printf("%d\n", cnt);
	for (int i = 0; i < cnt; i++)printf("%04d %d %.3lf %.3lf\n", ans[i].id, ans[i].members, ans[i].avgS, ans[i].avgA);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值