PAT甲级 1114 Family Property 并查集

在这里插入图片描述
在这里插入图片描述

题目大意:

给出n个人的家庭信息id, f_id, m_id, c_num, child1,child2… ,num, area。
分别代表这个人的id,父亲的id,母亲的id,子女的个数,子女id,总共拥有的房产数,房产的总面积。
我们要求出总共有几个不同的家庭,并输出每个家庭中id最小成员的id,家庭成员数,平均房产数,平均房产面积。

思路:

模拟+并查集的思路。

代码如下:

//并查集+离线
#include<iostream>
#include<algorithm>
#include<vector>
#include<stdio.h>
#define INF 0x3f3f3f3f
using namespace std;

int n;
int fa[10005];
int flag[10005]={0};


struct family{
    int min_id;
    int sum;//总人数
    int num,area;//总房产数,总面积
    double avg_num,avg_area;//平均房产数,平均面积
    family(){
        num=area=sum=0;
        min_id=INF;
    }
};

int findfather(int x){
    if(x!=fa[x]){
        return findfather(fa[x]);
    }else{
        return x;
    }
}

void _union(int a,int b){
    int aa=findfather(a);
    int bb=findfather(b);
    if(aa!=bb){
        fa[aa]=bb;
    }
}

vector<family> vec;

bool cmp(family a,family b){
    if(a.avg_area>b.avg_area){
        return true;
    }else if(a.avg_area==b.avg_area){
        return a.min_id<b.min_id;
    }
    return false;
}

int main(){
    for(int i=0;i<10005;i++){
        fa[i]=i;
    }
    cin>>n;
    vec.resize(10005);
    int id[1005],f_id[1005],m_id[1005],k[1005],c_id[1005][6],num[1005],area[1005];
    for(int i=0;i<n;i++){
        cin>>id[i]>>f_id[i]>>m_id[i]>>k[i];
        if(f_id[i]!=-1){
            _union(id[i],f_id[i]);
        }
        if(m_id[i]!=-1){
            _union(id[i],m_id[i]);
        }
        for(int j=0;j<k[i];j++){
            cin>>c_id[i][j];
            _union(id[i],c_id[i][j]);
        }
        cin>>num[i]>>area[i];
    }

    for(int i=0;i<n;i++){
        int sum=0;
        int father=findfather(id[i]);
        if(findfather(id[i])==id[i]){
            if(flag[id[i]]==0){
                sum++;
            }
        }
        if(findfather(id[i])!=id[i]){
            if(flag[id[i]]==0){
                sum++;
            }
        }
        flag[id[i]]=1;
        if(f_id[i]!=-1){
            if(findfather(f_id[i])!=f_id[i]){
                if(flag[f_id[i]]==0){
                    sum++;
                }
            }
            if(findfather(f_id[i])==f_id[i]){
                if(flag[f_id[i]]==0){
                    sum++;
                }
            }
            flag[f_id[i]]=1;
        }
        if(m_id[i]!=-1){
            if(findfather(m_id[i])!=m_id[i]){
                if(flag[m_id[i]]==0){
                    sum++;
                }
            }
            if(findfather(m_id[i])==m_id[i]){
                if(flag[m_id[i]]==0){
                    sum++;
                }
            }
            flag[m_id[i]]=1;
        }
        for(int j=0;j<k[i];j++){
            if(findfather(c_id[i][j])!=c_id[i][j]){
                if(flag[c_id[i][j]]==0){
                    sum++;
                }
            }
            if(findfather(c_id[i][j])==c_id[i][j]){
                if(flag[c_id[i][j]]==0){
                    sum++;
                }
            }
            flag[c_id[i][j]]=1;
        }
        if(id[i]<vec[father].min_id){
            vec[father].min_id=id[i];
        }
        if(f_id[i]!=-1&&f_id[i]<vec[father].min_id){
            vec[father].min_id=f_id[i];
        }
        if(m_id[i]!=-1&&m_id[i]<vec[father].min_id){
            vec[father].min_id=m_id[i];
        }

        for(int j=0;j<k[i];j++){
            if(c_id[i][j]<vec[father].min_id){
                vec[father].min_id=c_id[i][j];
            }
        }
        vec[father].sum+=sum;
        vec[father].num+=num[i];
        vec[father].area+=area[i];
    }

    int tot=0;
    for(int i=0;i<10005;i++){
        if(vec[i].sum!=0){
            tot++;
            vec[i].avg_num=(double)vec[i].num/(double)vec[i].sum;
            vec[i].avg_area=(double)vec[i].area/(double)vec[i].sum;
        }
    }

    cout<<tot<<endl;
    sort(vec.begin(),vec.end(),cmp);
    for(int i=0;i<10005;i++){
        if(vec[i].sum!=0){
            printf("%04d %d %.3lf %.3lf",vec[i].min_id,vec[i].sum,vec[i].avg_num,vec[i].avg_area);
            cout<<endl;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值