【ACWing】1604. 家产

题目地址:

https://www.acwing.com/problem/content/description/1606/

这次,需要你帮我们整理关于家庭财产方面的数据。给定每个人的家庭成员以及他/她自己名字下的不动产(地产)信息,我们需要知道每个家庭的成员数,以及人均不动产面积和人均房产套数。

输入格式:
第一行包含整数 N N N
接下来 N N N行,每行包含一个拥有房产的人员的信息,格式如下:
ID Father Mother k Child_1 ... child_k M_estate Area
其中ID是每个人的独一无二的 4 4 4位数标识号,Father和Mother是这个人的父母的 ID 号(父母去世则用 − 1 -1 1代替), k k k是孩子数量,Child_i是孩子的ID,M_estate是其名下房产数量,Area是其名下房产的总面积。

输出格式:
每行输出一个家庭的相关房产信息,格式如下:
ID M AVG_sets AVG_area
其中ID是家庭成员中编号最小的成员编号,M是家庭成员数,AVG_sets是人均房产套数,AVG_area是人均房产面积。
两个平均数都要保留三位小数。
按人均房产面积降序顺序输出所有家庭信息。
当存在人均房产面积相同的情况时,按ID升序顺序排序。

数据范围:
1 ≤ N ≤ 1000 1≤N≤1000 1N1000
0 ≤ k ≤ 5 0≤k≤5 0k5
每个人名下房产不超过 100 100 100套,
每个人名下房产总面积不超过 50000 50000 50000

思路是并查集。将家庭关系用并查集维护,并且开若干个数组,记录每个家庭的人数、最小ID、房产总套数和房产总面积。最后做一个归总。注意比较人均面积的时候,可以用整数乘法来做,而不是除法,因为比较double是不精确的。代码如下:

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

const int N = 10010;
int n;
int p[N], cnt[N], cnt_house[N], area[N], min_id[N];

int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }

void init(int x) {
  if (!~p[x]) p[x] = x;
}

void merge(int x, int y) {
  int px = find(x), py = find(y);
  if (px == py) return;
  p[px] = py;
  cnt[py] += cnt[px];
  cnt_house[py] += cnt_house[px];
  area[py] += area[px];
  min_id[py] = min(min_id[px], min_id[py]);
}

struct Info {
  int ID;
  int M;
  int TOT_CNT;
  int TOT_AREA;
};

int main() {
  for (int i = 0; i < N; i++) {
    p[i] = -1;
    cnt[i] = 1;
    min_id[i] = i;
  }
  scanf("%d", &n);
  for (int i = 1; i <= n; i++) {
    int id, fa, mo, k;
    scanf("%d%d%d%d", &id, &fa, &mo, &k);
    init(id);
    if (~fa)
      init(fa), merge(id, fa);
    if (~mo)
      init(mo), merge(id, mo);
    for (int j = 1; j <= k; j++) {
      int ch;
      scanf("%d", &ch);
      init(ch);
      merge(id, ch);
    }
    int c, a;
    scanf("%d%d", &c, &a);
    int pid = find(id);
    cnt_house[pid] += c;
    area[pid] += a;
  }

  vector<Info> v;
  for (int i = 0; i < N; i++)
    if (p[i] == i) {
      Info info;
      info.ID = min_id[i];
      info.M = cnt[i];
      info.TOT_CNT = cnt_house[i];
      info.TOT_AREA = area[i];
      v.push_back(info);
    }

  sort(v.begin(), v.end(), [&](Info &x1, Info &x2) {
    if (x1.TOT_AREA * x2.M != x2.TOT_AREA * x1.M) {
      return x1.TOT_AREA * x2.M > x2.TOT_AREA * x1.M;
    }
    return x1.ID < x2.ID;
  });
  printf("%lu\n", v.size());
  for (auto &info : v) {
    printf("%04d %d %.3lf %.3lf\n", info.ID, info.M,
           (double)info.TOT_CNT / info.M, (double)info.TOT_AREA / info.M);
  }
}

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn),空间 O ( n ) O(n) O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值