PAT A1114 Family Property

PAT A1114 Family Property

在这里插入图片描述

Sample Input:

10
6666 5551 5552 1 7777 1 100
1234 5678 9012 1 0002 2 300
8888 -1 -1 0 1 1000
2468 0001 0004 1 2222 1 500
7777 6666 -1 0 2 300
3721 -1 -1 1 2333 2 150
9012 -1 -1 3 1236 1235 1234 1 100
1235 5678 9012 0 1 50
2222 1236 2468 2 6661 6662 1 300
2333 -1 3721 3 6661 6662 6663 1 100

Sample Output:

3
8888 1 1.000 1000.000
0001 15 0.600 100.000
5551 4 0.750 100.000
  • 思路 1:并查集(带计数版)见 A1118 Birds and Forest
    step 1. 输入数据:三个数组inputIdf_numf_ereainputId[i]代表:第i组家庭的首ID;f_num[i]代表:第i组家庭的房产个数;f_area[i]代表:第i组家庭的房产面积
    step 2. 整合数据:从头遍历这几组数据:
      2-1 将每个小家庭的房产数房产面积累加如大家庭上(大家庭的id为find(inputId[i]);因为Union函数中每次都选id小的做为根:rx<ry,所以这个id一定是整个家庭里最小的)
      2-2 写入家庭总人数,即-father[find(id)]
      2-3 把这个大家庭标记上fam[id].flag = true;
    step 3. 先按flag位排序将无效数据筛选掉,再进行下一步处理
    step 4. 处理数据:求出每个大家庭的平均房产平均房产面积
    step 5. 然后按题目要求:房产面积降序,id升序 , 排序、输出即可

  • code 1:

#include <bits/stdc++.h> 
using namespace std;
const int maxn = 10100;
int father[maxn];
struct family{
	int id, memNum, num, area;
	double avNum, avArea;
	bool flag;
	family(){id=maxn;}
}fam[maxn]; 
int find(int x){
	while(father[x] >= 0){
		x = father[x];
	}
	return x;
}
void Union(int x, int y){
	int rx = find(x);
	int ry = find(y);
	if(rx != ry){
		if(rx > ry){
			father[ry]+=father[rx];
			father[rx]=ry;
		}
		else{
			father[rx]+=father[ry];
			father[ry]=rx;
		}	
	}
}
bool cmp(family a, family b){
	return a.flag > b.flag;
}
bool cmp1(family a, family b){
	return a.avArea != b.avArea ? a.avArea > b.avArea : a.id < b.id; 
}
int inputId[maxn], f_num[maxn], f_area[maxn];
int main(){
	int n; 
	scanf("%d", &n);
	fill(father, father+maxn, -1);
	for(int i = 0; i < n; ++i){	//1
		int fa, ma, nc, tmpc;
		scanf("%d %d %d %d", &inputId[i], &fa, &ma, &nc);
		if(fa != -1) Union(inputId[i], fa);
		if(ma != -1) Union(inputId[i], ma);
		for(int j = 0; j < nc; ++j){
			scanf("%d", &tmpc);
			Union(inputId[i], tmpc);
		}
		scanf("%d %d", &f_num[i], &f_area[i]);
	}
	for(int i = 0; i < n; ++i){	//2
		int id = find(inputId[i]);
		fam[id].id = id;
		fam[id].num += f_num[i];
		fam[id].area += f_area[i];
		fam[id].memNum = -father[id];
		fam[id].flag = true;
	}
	sort(fam, fam+maxn, cmp);	//3
 	int cnt = 0;	
	for(int i = 0; i < n && fam[i].flag; ++i){	//4 
		fam[i].avNum = (double)fam[i].num / fam[i].memNum;
		fam[i].avArea = (double)fam[i].area / fam[i].memNum;
		cnt++;
	}
	sort(fam, fam+maxn, cmp1); //5 
	printf("%d\n", cnt);
	for(int i = 0; i < cnt; ++i){
		printf("%04d %d %.3f %.3f\n", fam[i].id, fam[i].memNum, fam[i].avNum, fam[i].avArea);
	}
	return 0;
}
  • 思路 2:普通并查集
    查询家庭人数:通过在结构体中增设一个set<int> family;,来获得每个家庭的成员,进而得到人数
    step 1: 输入n个小家庭,insert成员
    step 2:将n个小家庭汇聚成大家庭,成员insert进去,并将大家庭的编号(root)push进一个vector
    step 3:对vector下标排序,输出

  • T2 code:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10010;
int father[maxn];
struct Peo{
	int id, sets, area;
	unordered_set<int> family;
}peo[maxn];
struct Fam{
	int id;
	double num, sets, area;
	unordered_set<int> family;
}fam[maxn];

void Init(){
	for(int i = 0; i < maxn; ++i) father[i] = i;
}
int FindFather(int x){
	int tmp = x;
	while(father[x] != x){
		x = father[x];
	}
	while(father[tmp] != tmp){
		int tmp2 = tmp;
		tmp = father[tmp];
		father[tmp2] = x;
	}
	return x;
}
void Union(int a, int b){
	int fa = FindFather(a);	
	int fb = FindFather(b);
	if(fa < fb){
		father[fb] = fa;
	}else{		
		father[fa] = fb;
	}
}
bool cmp(int a, int b){
	double avg1 = fam[a].area / fam[a].family.size();
	double avg2 = fam[b].area / fam[b].family.size();
	return avg1 != avg2 ? avg1 > avg2 : fam[a].id < fam[b].id;
}
bool cnt_fam[maxn];
int main(){
	int n;
	scanf("%d", &n);
	Init();
	for(int i = 0; i < n; ++i){
		int id, fa, ma, k, num_e, size_e;
		scanf("%d %d %d %d", &id, &fa, &ma, &k);
		peo[i].family.insert(id);
		if(fa != -1){
			Union(id, fa); 
			peo[i].family.insert(fa);
		}
		if(ma != -1){
			Union(id, ma); 
			peo[i].family.insert(ma);
		}
		for(int j = 0; j < k; ++j){
			int child;
			scanf("%d", &child);
			Union(id, child);
			peo[i].family.insert(child);
		}
		peo[i].id = id;
		scanf("%d %d", &peo[i].sets, &peo[i].area);
	}	
	vector<int> f; 
	for(int i = 0; i < n; ++i){
		int r = FindFather(peo[i].id);
		if(cnt_fam[r] == false){
			f.push_back(r);
			cnt_fam[r] = true;
		}
		fam[r].id = r;
		fam[r].family.insert(peo[i].family.begin(), peo[i].family.end());
		fam[r].sets += peo[i].sets;
		fam[r].area += peo[i].area;	
	}
	sort(f.begin(), f.end(), cmp);
	printf("%d\n", f.size());
	for(int i = 0; i < f.size(); ++i){
		int now = f[i];
		int num = fam[now].family.size();
		printf("%04d %d %.3f %.3f\n", fam[now].id, num, fam[now].sets / num, fam[now].area / num);
	}
	return 0;
}
  • T3 code: 直接用结果体作为father,结束是累加出每个大家庭的数据,放到一个vector中排序输出
#include <bits/stdc++.h>
using namespace std;
//const int maxn = 1010;  //不止有1000个人,N:家庭数
const int maxn = 100010;
int cnt[maxn], ans_sets[maxn], ans_area[maxn];
unordered_map<int, int> get_id, get_name;
struct Fam
{
    int r, np, num_set, area;
    double avg_set, avg_area;
}fam[maxn];
void Init()
{
    for(int i = 0; i < maxn; ++i)
    {
        fam[i].r = i;
    }
}
int FindFather(int x)
{
    int tmp = x;
    while(fam[x].r != x)
    {
        x = fam[x].r;
    }
    while(fam[tmp].r != tmp)
    {
        int tmp2 = tmp;
        tmp = fam[tmp].r;
        fam[tmp2].r = x;
    }
    return x;
}
void Union(int a, int b)
{
    int fa = FindFather(a), fb = FindFather(b);
    if(fa != fb)
    {
        if(get_name[fa] < get_name[fb]) fam[fb].r = fa; //这里必须使用原名字比大小,映射来的没有大小关系
        else fam[fa].r = fb;
    }
}
int idex = 0;
int Change(int id)
{
    if(get_id.find(id) == get_id.end())
    {
        get_id[id] = idex;
        get_name[idex] = id;
        return idex++;
    }else return get_id[id];
}
bool cmp(Fam a, Fam b)
{
    return a.avg_area != b.avg_area ? a.avg_area > b.avg_area : a.r < b.r;
}
int main()
{
    int n;
    scanf("%d", &n);
    Init();
    for(int i = 0; i < n; ++i)
    {
        int tid, other, nch;
        scanf("%d", &tid);
        tid = Change(tid);
        for(int j = 0; j < 2; ++j)
        {
            scanf("%d", &other);
            if(other != -1) Union(tid, Change(other));
        }
        scanf("%d", &nch);
        for(int j = 0; j < nch; ++j)
        {
            scanf("%d", &other);
            Union(tid, Change(other));
        }
        scanf("%d %d", &fam[tid].num_set, &fam[tid].area);
    }
    for(int i = 0; i < idex; ++i)
    {
        int r = FindFather(i);
        cnt[r]++;
        ans_sets[r] += fam[i].num_set;
        ans_area[r] += fam[i].area;
    }
    vector<Fam> ans; 
    for(int i = 0; i < idex; ++i)
    {
        int r = FindFather(i);
        if(cnt[r] != 0)
        {
            ans.push_back(Fam{get_name[r], cnt[r], 0, 0, 1.0*ans_sets[r]/cnt[r], 1.0*ans_area[r]/cnt[r]});
            cnt[r] = 0;
        }
    }
    sort(ans.begin(), ans.end(), cmp);
    printf("%d\n", ans.size());
    for(int i = 0; i < ans.size(); ++i)
    {
        printf("%04d %d %.3f %.3f\n", ans[i].r, ans[i].np, ans[i].avg_set, ans[i].avg_area);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值