并查集的题目

/*
题意:有很多组学生,在同一个组的学生经常会接触,也会有新的同学的加入。
但是SARS是很容易传染的,只要在该组有一位同学感染SARS,那么该组的所有同学都被认为得了SARS。
已知编号为0的同学是得了SARS的,现在的任务是计算出有多少位学生感染SARS了。
思路:使用并查集
*/


#define _CRT_SECURE_NO_WARNINGS // 让编译环境忽略对scanf的安全检查


#include <iostream>
#include <fstream>
#include <cstdio>
using namespace std;
struct UFSNode
{
int data; //结点对应顶点编号
int rank; //结点对应秩(并查集树的深度)
int parent; //结点对应双亲下标
int relation; //与上层节点的关系
int total; //以该节点为根的子树(包括该结点自己)的结点的个数
}; //并查集树的结点类型


class UFSet
{
protected:
int n;
UFSNode* tree;
public:
UFSet(int n);
~UFSet();
int Find(int x);
void Union(int x, int y);
int GetAnswer();
};
UFSet::UFSet(int n)
{
this->n = n;
tree = new UFSNode[n];
for (int i = 0; i < n; i++) //顶点编号为0~(n-1)
{
tree[i].rank = 0; //秩初始化为0
tree[i].parent = i; //双亲初始化指向自已
tree[i].relation = 0; //i自己是一类,它的父节点此时就是它自己,属于同一类
tree[i].total = 1; //该节点为根的子树的节点个数初始化为1,因为目前该节点单独作为一棵树
}
}
UFSet::~UFSet()
{
delete[] tree;
}


int UFSet::Find(int x)
{
int temp = tree[x].parent; // 将x父节点的下标存入temp
if (x != tree[x].parent) //若双亲不是自已
{
tree[x].parent = Find(tree[x].parent);//递归在双亲中找x
return tree[x].parent;
}
else
{
return x;
}
}


void UFSet::Union(int x, int y)
{
int rootx = Find(x); // 找到下标为x的元素的根节点下标rootx
int rooty = Find(y); // 找到下标为y的元素的根节点下标rooty
if (rootx == rooty) // 已合并,还搞个毛,直接返回
{
return;
}
if (tree[rootx].rank > tree[rooty].rank) //rooty结点的秩(深度)小于rootx结点的秩
{
tree[rooty].parent = rootx; //将rooty连到rootx结点上,rootx作为rooty的孩子结点
tree[rootx].total += tree[rooty].total; //以rootx为根节点的子树的结点数量要加上以rooty为跟的子树的结点数量
}
else //rooty结点的秩大于等于rootx结点的秩
{
tree[rootx].parent = rooty; //将rootx连到rooty结点上,rooty作为rootx的孩子结点
tree[rooty].total += tree[rootx].total; //以rooty为根节点的子树的结点数量要加上以rootx为跟的子树的结点数量
if (tree[rootx].rank == tree[rooty].rank) //rootx和rooty结点的秩(深度)相同
{
tree[rooty].rank++; //rooty结点的秩(深度)增1
}
}
}


int UFSet::GetAnswer()
{
int r = Find(0); //已知0号同学感染了SARS,找到0号同学的根节点r
return tree[r].total; //返回以r为根的子树的结点数量,就是患病人数
}


int main()
{
//ifstream cin("Text.txt");
int n = 0; // 总共n个人
int m = 0;
cin >> n >> m;
while (n > 0 && m >= 0) 
{
UFSet ufs(n);
int person1 = 0, person2 = 0;
for (int i = 0; i < m; i++)
{
int count = 0;
cin >> count;
cin >> person1;
for (int j = 1; j < count; j++)
{
cin >> person2;
ufs.Union(person1, person2);
person1 = person2;
}
}
cout << ufs.GetAnswer() << "\n";
cin >> n >> m;
}
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值