PAT A1114 Family Property (25 分) 并查集

60 篇文章 0 订阅

    题目大意:给出N个人的信息,信息中包括他的父母和子女的id(4位数),以及他名下的房产数量和面积。求出一共有多少个家庭,以及每个家庭的平均房产数和平均房产面积,并输出这个家庭中id最小的成员。

    并查集问题,一开始看到 N<=1000,id是四位数,考虑能不能通过对应来缩小范围,但是这是不可以的,因为包括他的父母和子女在内,远超过N个人。所以还是只能从0遍历到9999, 输入的同时要记录该编号出现过,否则从0遍历到9999会遍历到没出现的编号。之后就是统计每个家庭的根节点的房产数量和面积,注意在遍历时只有根节点与当前节点不同才能加上他的房产,否则会造成根节点的重复计算。最后还要记录每个根节点对应的最小id。虽然逻辑并不复杂,但是写起来还是一堆bug。

AC代码:

#include <vector>
#include <algorithm>
#include <cstdio>

using namespace std;

const int MAXN = 10010;
int parent[MAXN];

int findParent(int p)
{
    while(p != parent[p])
    {
        parent[p] = parent[parent[p]];
        p = parent[p];
    }
    return p;
}

void unionElement(int a, int b)
{
    int aRoot = findParent(a);
    int bRoot = findParent(b);
    parent[aRoot] = bRoot;
}

struct family
{
    int smallestId;
    int cnt;
    int totalSets;
    int totalAreas;
    double avgSets;
    double avgAreas;
    family(int smallestId, int cnt, int totalSets, int totalAreas): smallestId(smallestId), cnt(cnt), totalSets(totalSets), totalAreas(totalAreas), avgSets(totalSets * 1.0 / cnt), avgAreas(totalAreas * 1.0 / cnt){};
    bool operator <(const family& other)
    {
        if(this->avgAreas != other.avgAreas) return this->avgAreas > other.avgAreas;
        else return this->smallestId < other.smallestId;
    }
};

int main()
{
    int N;
    scanf("%d\n", &N);
    int sets[MAXN] = {0};
    int areas[MAXN] = {0};
    int roots[MAXN] = {0};
    int smallestId[MAXN] = {0};
    bool hasAppeared[MAXN] = {0};
    fill(smallestId, smallestId + MAXN, 1e5);
    for (int i = 0; i < MAXN; ++i)
        parent[i] = i;
    for (int i = 0; i < N; ++i)
    {
        int name, father, mother, childNum;
        scanf("%d%d%d%d", &name, &father, &mother, &childNum);
        hasAppeared[name] = true;
        if(father > -1)
        {
            hasAppeared[father] = true;
            unionElement(name, father);
        }
        if(mother > -1)
        {
            hasAppeared[mother] = true;
            if(father > -1) unionElement(mother, father);
            else unionElement(name, mother);
        }
        for (int j = 0; j < childNum; ++j)
        {
            int child;
            scanf("%d", &child);
            hasAppeared[child] = true;
            unionElement(child, name);
        }
        scanf("%d%d", &sets[name], &areas[name]);
    }
    for (int i = 0; i < MAXN; ++i)
    {
        if(hasAppeared[i])
        {
            int root = findParent(i);
            roots[root]++;
            if(root != i) sets[root] += sets[i];
            if(root != i) areas[root] += areas[i];
            if(smallestId[root] > i) smallestId[root] = i;
        }
    }
    vector<family> v;
    for (int i = 0; i < MAXN; ++i)
        if(roots[i] > 0) v.push_back(family(smallestId[i], roots[i], sets[i], areas[i]));
    sort(v.begin(), v.end());
    printf("%d\n", v.size());
    for (int i = 0; i < v.size(); ++i)
        printf("%04d %d %.3f %.3f\n", v[i].smallestId, v[i].cnt, v[i].avgSets, v[i].avgAreas);
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值