PAT A1114 Family Property [并查集]

题目描述

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

分析

  • 维护的是亲属关系,只要是有亲属关系,则属于这个集合,不用管这是是父母还是孩子,反正有亲属关系就好了
    • \(fa[i]=i\) 就算事先还没有明确元素个数,也可以先初始化了再说,也就是循环到\(maxn\)
    • 然后输入一个亲属结点(父母孩子),就执行\(merge(id, xxx)\)
  • \(data\)结构体数组接收数据,同时进行\(merge\)操作
  • \(ans\)结构体数组统计信息,里面有很多坑,看代码吧
    • 因为之前是循环到\(maxn\),所以用了\(vis\)数组来标记有效结点
    • 同时加\(flag\)变量标记根结点
#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn = 1e5;

int fa[maxn];
bool vis[maxn];
int n,k,cnt;

struct Data{
    int id, fid, mid, num, area, cid[10];
}data[1005];

struct node {
    int id, cnt;
    double num, area;
    bool flag;
}ans[maxn];

int find(int x){
    int r = x;
    while(x != fa[x]) x = fa[x];
    while(r != fa[r]){
        int t = r;
        r = fa[r];
        fa[t] = x;
    }
    return x;
}

void merge(int x, int y){
    int fx = find(x);
    int fy = find(y);
    if(fx!=fy) fa[max(fx,fy)] = min(fx,fy); //较小编号的作为祖先
}

int cmp(node a, node b) {
    if(a.area != b.area) return a.area > b.area;
    return a.id < b.id;
}

int main() {
    int n, k, cnt = 0;
    scanf("%d", &n);
    for(int i = 0; i < maxn; i++) fa[i] = i; //当结点数未定时也可以初始化
    //用data结构体保存读入的数据,注意data的大小只有n,不是maxn
    for(int i = 0; i < n; i++) {
        scanf("%d %d %d %d", &data[i].id, &data[i].fid, &data[i].mid, &k);
        vis[data[i].id] = true;
        if(data[i].fid != -1) {
            vis[data[i].fid] = true;
            merge(data[i].fid, data[i].id);
        }
        if(data[i].mid != -1) {
            vis[data[i].mid] = true;
            merge(data[i].mid, data[i].id);
        }
        for(int j = 0; j < k; j++) {
            scanf("%d", &data[i].cid[j]);
            vis[data[i].cid[j]] = true;
            merge(data[i].cid[j], data[i].id);
        }
        scanf("%d %d", &data[i].num, &data[i].area);
    }
    //用ans结构体统计信息,只保存根节点
    for(int i = 0; i < n; i++) {
        int id = find(data[i].id);
        ans[id].id = id;
        ans[id].num += data[i].num;
        ans[id].area += data[i].area;
        ans[id].flag = true;
    }
    //统计集合元素个数和根结点数目
    for(int i = 0; i < maxn; i++) {
        if(vis[i])
            ans[find(i)].cnt++;
        if(ans[i].flag)
            cnt++;
    }
    //计算平均
    for(int i = 0; i < maxn; i++) {
        if(ans[i].flag) {
            ans[i].num = (double)(ans[i].num * 1.0 / ans[i].cnt);
            ans[i].area = (double)(ans[i].area * 1.0 / ans[i].cnt);
        }
    }
    sort(ans, ans + maxn, cmp);
    printf("%d\n", cnt);
    for(int i = 0; i < cnt; i++)
        printf("%04d %d %.3f %.3f\n", ans[i].id, ans[i].cnt, ans[i].num, ans[i].area);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/doragd/p/11278479.html