栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

PAT甲级备考——并查集

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

PAT甲级备考——并查集

PAT甲级备考——并查集
  • 题目
    • 【1107】并查集
    • 【114】并查集

题目

PAT (Advanced Level) Practice

【1107】并查集
【1114】 并查集
【1118】并查集()

并查集知识点参考:https://zhuanlan.zhihu.com/p/29035169

【1107】并查集

1107 Social Clusters (30 分)
题⽬⼤意:有n个⼈,每个⼈喜欢k个活动,如果两个⼈有任意⼀个活动相同,就称为他们处于同⼀个社交⽹络。求这n个⼈⼀共形成了多少个社交⽹络。

#include
#include
#include
using namespace std;

int N;
vector fa, node_rank;
vector hobbies[1005];

// 初始化,每个节点的父节点是自身,每个节点目前的秩为1,即以该节点为父节点的子树深度为1
inline void init(){
    for(int i=1; i<=N; i++){
        fa[i] = i;
        node_rank[i] = 1;
    }
}
// 根据下标i,找到它的父亲根节点;迭代赋值
int find(int i){
    if(fa[i] == i) return i;
    else{
        fa[i] = find(fa[i]);
        return fa[i];
    }
}
// 合并两个子树a和b,先分别找到a和b的最深的根节点,将rank较小的树合并到rank较大的树下面,为了减少查找难度;
// 如果两个树一样大,则合并,并将父子树的rank值加1
void merge(int a, int b){
    int x = find(a), y = find(b);
    if(node_rank[x] >= node_rank[y]){
        fa[y] = x;
    }else if(node_rank[x] < node_rank[y]){
        fa[x] = y;
    }
    if(node_rank[x] == node_rank[y])
        node_rank[x]++;
}
bool cmp(int a, int b){
    return a>b;
}
int main(){
    
    // 1. 初始化
    cin>>N;
    fa.resize(N+1);
    node_rank.resize(N+1);
    init();
    
    // 2.读入每个人hobbies,根据hobby来合并
    int k, h;
    for(int i=1; i<=N; i++){
        scanf("%d:",&k); // 每个人有k个hobby
        while(k--){
            scanf("%d",&h);
            if(hobbies[h].size()!=0){ // 如果已经有人喜欢第h个hobby了,则将新人i合并到这个hobby的第一个人的子树下
                merge(hobbies[h][0], i);
            }
            hobbies[h].push_back(i); // 第h个hobby中加入新人i
        }
    }
    
    // 3. 统计多少组人
    int group_num = 0;
    vector groups(N+1);
    for(int i=1; i<=N; i++)
        groups[find(i)]++; // 找到每个人的根节点,相同的根节点意味着是同一组人,则该节点对应的人数++
    for(int i=1; i<=N; i++)
        if(groups[i]!=0) group_num++; // 如果某个根节点下有人则组数++
    
    sort(groups.begin(), groups.end(), cmp); //  groups内部按照人数倒叙排列
    
    // 4. 输出
    cout<
        printf("%d%s", groups[i], i==group_num-1?"n":" ");
    }
    
    return 0;
}
【114】并查集

题⽬⼤意:给定每个⼈的家庭成员和其⾃⼰名下的房产,请你统计出每个家庭的⼈⼝数、⼈均房产⾯积及房产套数。⾸先在第⼀⾏输出家庭个数(所有有亲属关系的⼈都属于同⼀个家庭)。随后按下列
格式输出每个家庭的信息:家庭成员的最⼩编号 家庭⼈⼝数 ⼈均房产套数 ⼈均房产⾯积。其中⼈均值要求保留⼩数点后3

两个数据结构:首先将所有的输入数据保存至data中,数据结构为自定义的person;进而转化成ans输出数组,数据结构为answer;
并查集的常规merge操作在输入阶段进行,且merge操作保障根节点一定是id值最小的人
维护visited数组,所有出现过的人均置为true;
ans数组中,is_root为true的人就是根节点,计算根节点对应的各种平均值

注意:
这里所有的亲属关系不区分爸爸妈妈(男女),亲属关系中的父子,在并查集中并不一定是父子,merge规则设定与”输出最小id的人“相适应;
printf(“%04d”, data) 将自动补齐0

#include
#include
#include
#include
#include
using namespace std;


// 输入数据的数据结构person
struct person{
    int id, fid, mid, m_estate, area;
    int child[10];
}data[1005];


// 输出答案的数据结构answer
struct answer{
    
    int id, number;
    double m_estate, area;
    bool is_root = false;
}ans[10000];

int N;
int fa[10000];  // 保存每个人的前驱节点的index
bool visited[10000]; // 由于输入10个人的信息,但是涉及的大于10人,因此维持visited数组,保存有谁出现过

void init(){
    
    for(int i=0; i<10000; i++){
        fa[i] = i;
    }
}
int find(int index){
    
    while(index != fa[index])
        index = fa[index];
    return index;
}
void merge(int a, int b){
    
    int root_a = find(a);
    int root_b = find(b);
    if(root_a > root_b)
        fa[root_a] = root_b;
    else if(root_a < root_b)
        fa[root_b] = root_a;
}
bool cmp(answer x, answer y){
    if(x.area != y.area){
        return x.area > y.area;
    }else{
        return x.id < y.id;
    }
}


int main(){
    
    cin>>N;
    init();
    int k, m_estate, area;
    for(int i=0; i
        scanf("%d %d %d %d", &data[i].id, &data[i].fid, &data[i].mid, &k);
        visited[data[i].id] = true;
        if(data[i].fid != -1){
            merge(data[i].fid,data[i].id);
            visited[data[i].fid] = true;
        }
        if(data[i].mid != -1){
            merge(data[i].mid,data[i].id);
            visited[data[i].mid] = true;
        }
        for(int ik=0; ik
            scanf("%d", &data[i].child[ik]);
            merge(data[i].child[ik], data[i].id);
            visited[data[i].child[ik]] = true;
        }
        scanf("%d %d", &data[i].m_estate, &data[i].area);
    }
    
    
    for(int i=0; i
        int r = find(data[i].id);
        ans[r].id = r;
        ans[r].m_estate += data[i].m_estate;
        ans[r].area += data[i].area;
        ans[r].is_root = true;
    }
    
    
    int group_number=0;
    for(int i=0; i<10000; i++){
        if(visited[i]){
            ans[find(i)].number+=1; // 如果i被访问过,则i的根节点find(i)对应的答案数组中,数目++
        }
        if(ans[i].is_root){
            group_number++; // 如果ans中节点对应的is_root为true,则是根节点,总的组数++
        }
    }
    cout< temp;
    for(int i=0; i<10000; i++){
        if(ans[i].is_root){
            ans[i].m_estate = (double)(ans[i].m_estate*1.0/ans[i].number);
            ans[i].area = (double)(ans[i].area*1.0/ans[i].number);
            temp.push_back(ans[i]);
        }
    }
    sort(temp.begin(), temp.end(), cmp);
    for(int i=0; i
        printf("%04d %d %.3f %.3fn", temp[i].id, temp[i].number, temp[i].m_estate, temp[i].area);
    }
    
    return 0;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/960504.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号