L2-007 家庭房产 - java

L2-007 家庭房产


时间限制
400 ms
内存限制
64 MB


题目描述:
给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。


输入格式:
输入第一行给出一个正整数N(≤1000),随后N行,每行按下列格式给出一个人的房产:

编号 父 母 k 孩子1 … 孩子k 房产套数 总面积

其中编号是每个人独有的一个4位数的编号;父和母分别是该编号对应的这个人的父母的编号(如果已经过世,则显示-1);k(0≤k≤5)是该人的子女的个数;孩子i是其子女的编号。


输出格式:
首先在第一行输出家庭个数(所有有亲属关系的人都属于同一个家庭)。随后按下列格式输出每个家庭的信息:

家庭成员的最小编号 家庭人口数 人均房产套数 人均房产面积

其中人均值要求保留小数点后3位。家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。


输入样例:
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


输出样例:
3
8888 1 1.000 1000.000
0001 15 0.600 100.000
5551 4 0.750 100.000


给定n个家族 求出共有几个宗族

输出时 按人均面积降序输出 若有并列 则按成员编号的升序输出


emmmmmmm

应该能见的出是并查集
因为需要找出有几个宗族 所有能说明这个可以往并查集想


既然并查集 且需要排序 那么就需要对象来存储
存什么呢

当前宗族的最小节点
当前宗族的人数
当前宗族的总房产套数
当前宗族的总房产面积

排序呢 就是按照题目的排序即可


因为不确定有多少个节点会被用到 所以一开始就直接设为1e4个
然后呢 用vis去标记是否用过该节点

输入时的 合并节点时 一定要注意 当前节点 的父母以及孩子是否都存在 (可能不存在哦)

然后就是 清点宗族节点的总套房数及总面积


import java.io.*;
import java.util.*;

public class Main
{
	static int N = (int) 1e4;
//	存储当前节点祖宗节点
	static int fa[] = new int[N + 10];
//	存储当前节点是否被用过
	static boolean vis[] = new boolean[N + 10];
//	存储节点信息
	static edge shu[] = new edge[N + 10];

	static class edge implements Comparable<edge>
	{
		int id; // 编号
		int ren; // 家庭人口
		double taofang; // 家庭套房数
		double mianji; // 家庭套房总面积

		public edge(int id, int ren, double taofang, double mianji)
		{
			this.id = id;
			this.ren = ren;
			this.mianji = mianji;
			this.taofang = taofang;
		}

		public String toString()
		{
			return id + " " + ren + " " + mianji + " " + taofang;
		}

		@Override
		public int compareTo(edge other)
		{
			double a = this.mianji / this.ren, b = other.mianji / other.ren;

			if (a > b)
				return -1;
			else if (a < b)
				return 1;

			return this.id - other.id;
		}

	}

//	寻找祖宗节点
	static int find(int x)
	{
		if (fa[x] != x)
			fa[x] = find(fa[x]);
		return fa[x];
	}

//	合并两个节点 将b划到a的宗谱下
	static void merge(int a, int b)
	{
		vis[a] = vis[b] = true;
		int x = find(a), y = find(b);
		if (x != y)
			fa[y] = x;
	}

	public static void main(String[] args) throws IOException
	{
//		初始化
		for (int i = 0; i <= N; i++)
		{
			fa[i] = i;
			shu[i] = new edge(i, 0, 0, 0);
		}

		int n = sc.nextInt();
		while (n-- > 0)
		{
			int id = sc.nextInt();
//			当前节点需要被用到 因为可能当前节点的父母全部去世了 并且还没有孩子
//												比较不雅的说法 但是有这种情况
			vis[id] = true;

			int father = sc.nextInt(), mother = sc.nextInt();
//			当前父母没有去世 就合并两个点
			if (father != -1) merge(father, id);
			if (mother != -1) merge(mother, id);

			int soncnt = sc.nextInt();
			while (soncnt-- > 0)
			{
				int son = sc.nextInt();
//				合并当前节点的子节点
				merge(id, son);
			}

			shu[id] = new edge(id, 0, sc.nextInt(), sc.nextInt());
		}

		for (int i = 0; i <= N; i++)
		{
//			当前这个点有被用到 (父母节点 当前节点 子节点)
			if (vis[i])
			{
//				寻找当前节点的祖宗节点
				int u = find(i);
//				当前宗族的编号替换为最小的
				shu[u].id = Math.min(shu[u].id, i);
//				当前宗族的人数+1
				shu[u].ren++;

//				如果当前的祖宗节点是自己的话 就不需要加上子辈的房屋面积以及套房数
				if (u == i) continue;
				shu[u].mianji += shu[i].mianji;
				shu[u].taofang += shu[i].taofang;
			}
		}

//		存储当前的宗族
		ArrayList<edge> ar = new ArrayList<edge>();
		for (int i = 0; i <= N; i++)
		{
//			如果当前的宗族有人那么就添加
			if (shu[i].ren > 0)
				ar.add(shu[i]);
		}
//		排序
		Collections.sort(ar);

//		输出
		out.println(ar.size());
		for (edge i : ar)
		{
			int x = i.ren;
			out.printf("%04d %d %.3f %.3f\n", i.id, x, i.taofang / x, i.mianji / x);
		}

		out.flush();
		out.close();
	}

	static InputReader sc = new InputReader();
	static PrintWriter out = new PrintWriter(System.out);

	static class InputReader
	{
		private InputStream inputStream = System.in;
		private byte[] buf = new byte[100000];
		private int curChar;
		private int numChars;

		public int getchar()
		{
			if (numChars == -1)
				throw new InputMismatchException();
			if (curChar >= numChars)
			{
				curChar = 0;
				try
				{
					numChars = inputStream.read(buf);
				} catch (IOException e)
				{
					throw new InputMismatchException();
				}
				if (numChars <= 0)
					return -1;
			}
			return buf[curChar++];
		}

		public int nextInt()
		{
			int a = 0, b = 1;
			int c = getchar();
			while (c < '0' || c > '9')
			{
				if (c == '-')
				{
					b = -1;
				}
				c = getchar();
			}
			while (c >= '0' && c <= '9')
			{
				a = (a << 1) + (a << 3) + (c ^ 48);
				c = getchar();
			}
			return a * b;
		}
	}
}

并查集
并查集

对象数组排序
对象排序
对象排序


如果有说错的 或者 不懂的 尽管提 嘻嘻

一起进步!!!


闪现

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

谢谢 啊sir

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值