PAT (Advanced Level) Practise 1114 Family Property (25) 并查集orDFS

1114. Family Property (25)

时间限制
150 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

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 Child1 ... Childk 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; Childi'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

并查集,将所有有亲戚关系的节点全部合并到一个并查集里,子节点将地产的信息和人数信息也要合并到父节点里面去,但是感觉太长了。。。看网上有直接用DFS的

就七八十行,输了。。。



#include <cstdio>
#include <cstring>
#include <map>
#include <iostream>
#include <cmath>
#include <algorithm>

using namespace std;

struct node {
	int id, cou; //cou为集合中的元素数目
	double suma, sums;
	node() { cou = 0; suma = 0; sums = 0; }
	node(int id) : id(id) { cou = 0; suma = 0; sums = 0; }
}fam[10], f[11111], ans[11111];

const int INF = 0x7fffffff;
int N;

bool cmp(node a, node b) {
	if (fabs(a.suma - b.suma) < 1e-8) {
		return a.id < b.id;
	}
	else {
		return a.suma > b.suma;
	}
}

int getf(int x) {
	return f[x].id == x ? x : f[x].id = getf(f[x].id);
}

void Merge(int x, int y) {
	int xx = getf(x), yy = getf(y);
	int fx = min(xx, yy), fy = max(xx, yy);
	if (fx != fy) {
		f[fy].id = f[fx].id; //父节点吸收吸收子节点
		f[fx].sums += f[fy].sums;
		f[fx].suma += f[fy].suma;
		f[fx].cou += f[fy].cou;
	}
}

int main()
{
	scanf("%d", &N);
	map<int, int> m; //用来记录ID的出现情况,m[i]不为零说明出现过
	bool vis[10001]; //用来记录一个ID的重复情况,为true时说明以前出现过

	//并查集初始化
	for (int i = 0; i <= 9999; i++) {
		f[i].id = i;
	}

	memset(vis, false, sizeof(vis));
	for (int t = 1; t <= N; t++) {
		int id, fa, ma, k, len, Set, Area, minn, index, ff;
		scanf("%d%d%d", &id, &fa, &ma);
		k = 0; //fam数组的长度
		minn = INF; //minn用来存根节点的最小值
		index = 0; //index为输入的一组ID里面根节点最小的所在下标
		m[id]++;  //说明这个ID出现过
		ff = getf(id);
		if (ff < minn) {
			minn = ff;
			index = 0;
		}
		fam[k++] = node(id);
		if (fa != -1) {
			m[fa]++;
			fam[k] = node(fa);
			ff = getf(fa);
			if (ff < minn) {
				minn = ff;
				index = k;
			}
			k++;
		}
		if (ma != -1) {
			m[ma]++;
			fam[k] = node(ma);
			ff = getf(ma);
			if (ff < minn) {
				minn = ff;
				index = k;
			}
			k++;
		}

		scanf("%d", &len);
		while (len--) {
			scanf("%d", &fam[k].id);
			m[fam[k].id]++;
			ff = getf(fam[k].id);
			if (ff < minn) {
				minn = ff;
				index = k;
			}
			k++;
		}
		scanf("%d%d", &Set, &Area);
		int c = 0;
		for (int i = 0; i < k; i++) {
			Merge(fam[index].id, fam[i].id);

			//在集合里去重,也就是以前加入集合的不用再加入了
			if (!vis[fam[i].id]) {
				vis[fam[i].id] = true;
				c++;
			}
		}
		int root = getf(fam[index].id);
		f[root].sums += Set;
		f[root].suma += Area;
		f[root].cou += c;
	}
	for (int i = 0; i <= 9999; i++) {
		f[i].id = getf(f[i].id);
	}
	int LEN = 0;
	for (int i = 0; i <= 9999; i++) {
		//说明m[i]在输入的数里面
		if (m[i] != 0) {
			if (f[i].id == i) {
				ans[LEN] = f[i];
				ans[LEN].suma /= ans[LEN].cou;
				ans[LEN].sums /= ans[LEN].cou;
				LEN++;
			}
		}
	}
	sort(ans, ans + LEN, cmp);
	printf("%d\n", LEN);
	for (int i = 0; i < LEN; i++) {
		printf("%04d %d %.3f %.3f\n", ans[i].id, ans[i].cou, ans[i].sums, ans[i].suma);
	}
	return 0;
}


用DFS直接找连通域并累加人数和地产信息


#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 10000 + 10;
int N, C, Set[maxn], Area[maxn], ID;
double S, A;
bool f[maxn];

struct node {
	int id, cou;
	double a_s, a_a;
	node(int id = 0, int cou = 0, double a_s = 0, double a_a = 0) : id(id), cou(cou), a_s(a_s), a_a(a_a) {};
}p[maxn];

bool cmp(node a, node b) {
	if (fabs(a.a_a - b.a_a) < 1e-8) {
		return a.id < b.id;
	}
	else {
		return a.a_a > b.a_a;
	}
}

vector<int> m[maxn];

void dfs(int x) {
	ID = min(ID, x);
	C++; //累加人数
	f[x] = false; //标记不再重走
	S += (1.0 * Set[x]); //累加地产信息,地产挂在第一个id头上,其他的都为0
	A += (1.0 * Area[x]);
	for (int i = 0; i < m[x].size(); i++) {
		if (f[m[x][i]]) {
			dfs(m[x][i]);
		}
	}
}

int main()
{
	scanf("%d", &N);
	memset(f, false, sizeof(f));
	for (int t = 0; t < N; t++) {
		int id, fa, ma, len, tem;
		scanf("%d%d%d", &id, &fa, &ma);
		f[id] = true;  //记录一个数出现过
		if (fa != -1) {
			f[fa] = true;
			m[id].push_back(fa);
			m[fa].push_back(id);
		}
		if (ma != -1) {
			f[ma] = true;
			m[id].push_back(ma);
			m[ma].push_back(id);
		}
		scanf("%d", &len);
		while (len--) {
			scanf("%d", &tem);
			f[tem] = true;
			m[id].push_back(tem);
			m[tem].push_back(id);
		}
		scanf("%d%d", &Set[id], &Area[id]);
	}
	int LEN = 0;
	//0 - 9999扫描
	for (int i = 0; i < 10000; i++) {
		//输入过的
		if (f[i]) {
			ID = 10000;
			C = 0;
			S = A = 0;
			dfs(i);
			p[LEN++] = node(ID, C, S / (1.0 * C), A / (1.0 * C));
		}
	}
	sort(p, p + LEN, cmp);
	printf("%d\n", LEN);
	for (int i = 0; i < LEN; i++) {
		printf("%04d %d %.3f %.3f\n", p[i].id, p[i].cou, p[i].a_s, p[i].a_a);
	}
	return 0;
}




你可能感兴趣的:(pat)