PTA---L2-007 家庭房产(并查集)

PTA—L2-007 家庭房产

直达链接点我!!!

思路

  • emmm,就是一道比较多细节的并查集题目吧,其他的没有什么了
  • 说下需要注意的几个点
  • 1.我们不能边输入边进行合并操作,而是需要先保存下各个输入的相关家庭的信息,而只将房产数据保存至户主名下
  • 2.当我们将二者合并时,由于题目需要输出最小编号,于是我们合并时,以最小的那个编号最为老大
  • 什么?你不明白老大什么意思?
    请看:
    比如我们开始输入2 1 3 1 4
    表示2为户主,1 3 为他的爹娘,4为他的孩子
    如果按照辈分存…
    辈分
    这样显然不是我们想要的,毕竟并查集的老大只有1个
    所以我们就将计就计,让最小编号的做老大
    所以会形成如下树
    最小编号老大
    按此思路—

AC代码

这里可能有别的快一点的方法,若出现一些错误,或者可以进行优化的,还请各位大佬指教。

#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
using namespace std;
struct bcj
{
    int count;                      //家庭人口数
    int anct;                     //老大的编号
    int htl;                        //房产套数
    double area;                    //房产面积
    bcj()
    {
        count = 1;
        anct = 0;
        htl = 0;
        area = 0;
    }
};
bcj a[10000];                   //并查集
void swap(int &x,int &y)
{
    int t = x;
    x = y;
    y = t;
}
void ini()
{
    for(int i=0;i<=10000;i++)
        a[i].anct = i;
}
int Find(int x)
{
    if(x == a[x].anct)
        return x;
    return a[x].anct = Find(a[x].anct);
}
void merge(int x,int y)                 //这里比较小的编号是老大
{
    if(y == -1)
        return ;
    x = Find(x);
    y = Find(y);
    if(x != y)
    {
        if(x > y)                               //当x大于y时,本来不应该是x为老大的,交换二人数值
            swap(x,y);
        a[y].anct = x;                      //x是老大
        a[x].count += a[y].count;           //当然要加上小弟的房产,人口咯
        a[x].htl += a[y].htl;
        a[x].area += a[y].area;
    }
}
struct peo
{
    int id;
    int count;
    double ahtl;
    double aarea;
    peo()
    {
        id = 0;
        count = 0;
        ahtl = 0;
        aarea = 0; 
    }
};
bool cmp(peo a,peo b)
{
    if(a.aarea == b.aarea)
        return a.id < b.id;
    return a.aarea > b.aarea;
}
int main()
{
	ini();
    int n,i,j;
    scanf("%d",&n);
    
    vector<int> b[n];						//存放第i个输入的家庭关系,留置所有房产输入完毕后再进行合并 
    //这里假设拥有房产的是老大...
    for(i=0;i<n;i++)
    {
    	//int p[10],t = 0;
        int id,fid,mid,k;
        scanf("%d %d %d %d",&id,&fid,&mid,&k);
        
        b[i].push_back(id);                              //存储每个可能做老大的人的编号,便于查找
        
        b[i].push_back(fid);
        b[i].push_back(mid);
        for(j=0;j<k;j++)
        {
            int cid;
            scanf("%d",&cid);
            b[i].push_back(cid);
        }
        int htl;
        double area;
        scanf("%d %lf",&htl,&area);
        a[id].area = area;
        a[id].htl = htl;
        
    }
    for(i=0;i<n;i++)
    {
    	int x = b[i][0];
    	for(j=1;j<b[i].size();j++)
    	merge(x,b[i][j]);
	}
    set<int> bk;
    //int book[1005],top = 0;                    //存储每个老大的编号
    peo book[1005];
	int top = 0;
    for(i=0;i<n;i++)
    {
        int x = Find(b[i][0]);                         //找到老大
        if(bk.count(x) == 0)           //存储老大
        {
            bk.insert(x);
            book[top].id = x;
            book[top].count = a[x].count;
            book[top].aarea = a[x].area/(double)a[x].count;
            book[top].ahtl = a[x].htl/(double)a[x].count;
            top++;
        }
    }
    printf("%d\n",top);
    sort(book,book+top,cmp);
    for(i=0;i<top;i++)
    {
        printf("%04d %d %.3f %.3f\n",book[i].id,book[i].count,book[i].ahtl,book[i].aarea);
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值